diff options
Diffstat (limited to 'app/src')
32 files changed, 1054 insertions, 0 deletions
diff --git a/app/src/androidTest/java/com/a404m/calculator/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/a404m/calculator/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..785fe9a --- /dev/null +++ b/app/src/androidTest/java/com/a404m/calculator/ExampleInstrumentedTest.kt @@ -0,0 +1,27 @@ +package com.a404m.calculator + +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( + "com.a404m.calculator", + appContext.packageName + ) + } +}
\ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8d7bca4 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> + + <application + 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.Calculator" + tools:targetApi="31"> + <activity + android:name=".MainActivity" + android:exported="true" + android:label="@string/app_name" + android:theme="@style/Theme.Calculator"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest>
\ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png Binary files differnew file mode 100644 index 0000000..2d94637 --- /dev/null +++ b/app/src/main/ic_launcher-playstore.png diff --git a/app/src/main/java/com/a404m/calculator/MainActivity.kt b/app/src/main/java/com/a404m/calculator/MainActivity.kt new file mode 100644 index 0000000..9a40e9b --- /dev/null +++ b/app/src/main/java/com/a404m/calculator/MainActivity.kt @@ -0,0 +1,27 @@ +package com.a404m.calculator + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.a404m.calculator.ui.page.HomePage +import com.a404m.calculator.ui.theme.CalculatorTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + CalculatorTheme { + HomePage() + } + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/a404m/calculator/MathHelper.kt b/app/src/main/java/com/a404m/calculator/MathHelper.kt new file mode 100644 index 0000000..fa6cfc7 --- /dev/null +++ b/app/src/main/java/com/a404m/calculator/MathHelper.kt @@ -0,0 +1,309 @@ +package com.a404m.calculator + +import android.util.Log +import com.a404m.calculator.MathHelper.Operator.Kind +import java.nio.charset.UnsupportedCharsetException + +object MathHelper { + private val operatorStrings = arrayOf( + '+', + '-', + '×', + '÷', + '%', + ) + private val numberStrings = arrayOf( + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '.', + ) + + private val plus = Operator( + '+', + Kind.PREFIX, + { + Operand(it.first().value) + } + ) + private val minus = Operator( + '-', + Kind.PREFIX, + { + Operand(-it.first().value) + } + ) + private val add = Operator( + '+', + Kind.INFIX, + { + Operand(it.first().value+it.last().value) + } + ) + private val sub = Operator( + '-', + Kind.INFIX, + { + Operand(it.first().value-it.last().value) + } + ) + private val mul = Operator( + '×', + Kind.INFIX, + { + Operand(it.first().value*it.last().value) + } + ) + private val div = Operator( + '÷', + Kind.INFIX, + { + Operand(it.first().value/it.last().value) + } + ) + private val rem = Operator( + '%', + Kind.INFIX, + { + Operand(it.first().value%it.last().value) + } + ) + private val operatorOrders = arrayOf( + arrayOf( + plus, + minus, + ), + arrayOf( + mul, + div, + rem, + ), + arrayOf( + add, + sub, + ) + ) + private val operators = arrayOf( + plus, + minus, + add, + sub, + mul, + div, + rem, + ) + + fun eval(expression: String): String { + return try { + parse(lex(expression)).eval().toString() + } catch (e: Exception) { + e.message ?: "Exception" + } + } + + private fun parse(lexed: ArrayList<Any>): Operator { + for (order in operatorOrders) { + if (lexed.size == 1) { + break + } + for (i in lexed.indices) { + val item = lexed[i] + if (item is BasicOperator) { + var op = item.toOperator( + lexed, + i + ) + if (op in order) { + op = op.cloneWithoutOperands() + Log.d( + "A404M", + "parse: $op" + ) + lexed[i] = op + when (op.kind) { + Kind.NONE -> {} + Kind.INFIX -> { + op.operands.add(lexed.removeAt(i - 1)) + op.operands.add(lexed.removeAt(i)) + } + + Kind.PREFIX -> { + op.operands.add(lexed.removeAt(i + 1)) + } + + Kind.POSTFIX -> { + op.operands.add(lexed.removeAt(i - 1)) + } + } + break + } + } + } + } + return if (lexed.size != 1) { + throw UnsupportedOperationException("lexed.size = ${lexed.size}: $lexed") + } else if (lexed.first() is Operator) { + lexed.first() as Operator + } else if (lexed.first() is Operand) { + plus.cloneWithoutOperands().cloneWithOperator(arrayListOf(lexed.first())) + } else { + throw UnsupportedOperationException("unsupported type ${lexed.first().javaClass}") + } + } + + private fun lex(expression: String): ArrayList<Any> { + val items = arrayListOf<Any>() + + var i = 0 + while (i < expression.length) { + when (val c = expression[i]) { + in numberStrings -> { + val start = i + while (++i < expression.length && expression[i] in numberStrings); + items.add( + Operand( + value = expression.substring( + start, + i + ).toDouble() + ) + ) + --i + } + + in operatorStrings -> { + items.add( + BasicOperator(c) + ) + } + + else -> throw UnsupportedCharsetException(c.toString()) + } + ++i + } + + return items + } + + private class Operator( + val operator: Char, + val kind: Kind, + val operate: (operands:List<Operand>)->Operand, + val operands: ArrayList<Any> = arrayListOf(), + ) { + fun cloneWithoutOperands():Operator{ + return Operator( + operator, + kind, + operate, + ) + } + + fun cloneWithOperator(operands: ArrayList<Any>): Operator { + return Operator( + operator, + kind, + operate, + operands, + ) + } + + fun eval(): Operand { + Log.d( + "A404M", + "eval: $operator $operands" + ) + if(operandSize() != operands.size){ + throw UnsupportedOperationException("Not enough operands") + } + + val evaledOperands = operands.map { + if(it is Operator){ + it.eval() + }else{ + it as Operand + } + } + + return operate(evaledOperands) + } + + fun operandSize(): Int { + return when (kind) { + Kind.INFIX -> 2 + Kind.PREFIX, Kind.POSTFIX -> 1 + Kind.NONE -> 0 + } + } + + override fun toString(): String { + return "$operator $kind $operands" + } + + enum class Kind { + NONE, + INFIX, + PREFIX, + POSTFIX, + } + } + + private class BasicOperator( + val operator: Char, + ) { + fun toOperator( + items: List<Any>, + i: Int + ): Operator { + val left = items.getOrElse( + i - 1, + { Any() }, + ) is Operand + + val right = items.getOrElse( + i + 1, + { Any() }, + ) is Operand + + val k:Kind + + if (left) { + if (right) { + k = Kind.INFIX + } else { + k = Kind.POSTFIX + } + } else if (right) { + k = Kind.PREFIX + } else { + k = Kind.NONE + } + + return operators.first { + it.operator == operator && it.kind == k + } + } + + override fun toString(): String { + return operator.toString(); + } + } + + private class Operand( + val value: Double, + ){ + override fun toString(): String { + if(value % 1 == 0.0){ + return "%.0f".format(value) + } + return value.toString() + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/a404m/calculator/model/CalcButtonModel.kt b/app/src/main/java/com/a404m/calculator/model/CalcButtonModel.kt new file mode 100644 index 0000000..435acef --- /dev/null +++ b/app/src/main/java/com/a404m/calculator/model/CalcButtonModel.kt @@ -0,0 +1,139 @@ +package com.a404m.calculator.model + +import com.a404m.calculator.MathHelper + +data class CalcButtonModel( + val text: String, + val weight:Float = 1F, + val op: (expression: String) -> String, +) { + companion object { + val K_0 = CalcButtonModel( + text = "0", + op = { + it + '0' + } + ) + val K_1 = CalcButtonModel( + text = "1", + op = { + it + '1' + } + ) + val K_2 = CalcButtonModel( + text = "2", + op = { + it + '2' + } + ) + val K_3 = CalcButtonModel( + text = "3", + op = { + it + '3' + } + ) + val K_4 = CalcButtonModel( + text = "4", + op = { + it + '4' + } + ) + val K_5 = CalcButtonModel( + text = "5", + op = { + it + '5' + } + ) + val K_6 = CalcButtonModel( + text = "6", + op = { + it + '6' + } + ) + val K_7 = CalcButtonModel( + text = "7", + op = { + it + '7' + } + ) + val K_8 = CalcButtonModel( + text = "8", + op = { + it + '8' + } + ) + val K_9 = CalcButtonModel( + text = "9", + op = { + it + '9' + } + ) + val K_PLUS = CalcButtonModel( + text = "+", + op = { + it + '+' + } + ) + val K_MINUS = CalcButtonModel( + text = "-", + op = { + it + '-' + } + ) + val K_MULTIPLY = CalcButtonModel( + text = "×", + op = { + it + '×' + } + ) + val K_DIVISION = CalcButtonModel( + text = "÷", + op = { + it + '÷' + } + ) + val K_REMINDER = CalcButtonModel( + text = "%", + op = { + it + '%' + } + ) + val K_EQUAL = CalcButtonModel( + text = "=", + op = { + MathHelper.eval(it) + } + ) + val K_DOT = CalcButtonModel( + text = ".", + op = { + it + '.' + } + ) + val K_C = CalcButtonModel( + text = "C", + op = { + "" + } + ) + val K_BACKSPACE = CalcButtonModel( + text = "⌫", + op = { + if (it.length <= 1) { + "" + } else { + it.substring( + 0, + it.length - 1, + ) + } + } + ) + val K_SWITCH_MODE = CalcButtonModel( + text = "\u2026", + op = { + it + } + ) + } +} diff --git a/app/src/main/java/com/a404m/calculator/ui/page/Home.kt b/app/src/main/java/com/a404m/calculator/ui/page/Home.kt new file mode 100644 index 0000000..ba9a21e --- /dev/null +++ b/app/src/main/java/com/a404m/calculator/ui/page/Home.kt @@ -0,0 +1,120 @@ +package com.a404m.calculator.ui.page + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +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.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.contentColorFor +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +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 com.a404m.calculator.model.CalcButtonModel +import com.a404m.calculator.ui.theme.CalculatorTheme +import com.a404m.calculator.ui.util.CalcGrid + +@Composable +fun HomePage(modifier: Modifier = Modifier) { + var expression by rememberSaveable { + mutableStateOf("") + } + Scaffold( + modifier = modifier, + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize(), + verticalArrangement = Arrangement.Bottom, + ) { + Text( + modifier = Modifier.padding(8.dp).fillMaxWidth(), + text = expression, + style = MaterialTheme.typography.titleLarge, + textAlign = TextAlign.Right, + fontSize = 35.sp, + ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 4.dp)) + CalcGrid( + modifier = Modifier + .padding(4.dp), + columns = 4, + items = arrayOf( + CalcButtonModel.K_C, + CalcButtonModel.K_BACKSPACE, + CalcButtonModel.K_REMINDER, + CalcButtonModel.K_DIVISION, + CalcButtonModel.K_7, + CalcButtonModel.K_8, + CalcButtonModel.K_9, + CalcButtonModel.K_MULTIPLY, + CalcButtonModel.K_4, + CalcButtonModel.K_5, + CalcButtonModel.K_6, + CalcButtonModel.K_MINUS, + CalcButtonModel.K_1, + CalcButtonModel.K_2, + CalcButtonModel.K_3, + CalcButtonModel.K_PLUS, + CalcButtonModel.K_0, + CalcButtonModel.K_DOT, + CalcButtonModel.K_SWITCH_MODE, + CalcButtonModel.K_EQUAL, + ), + ) { + val backColor = MaterialTheme.colorScheme.primary + Box( + modifier = Modifier + .padding(4.dp) + .height(70.dp) + .weight(it.weight) + .clip( + shape = RoundedCornerShape(10.dp), + ) + .background( + color = backColor, + shape = RoundedCornerShape(10.dp), + ) + .clickable { + expression = it.op(expression) + }, + contentAlignment = Alignment.Center, + ) { + Text( + text = it.text, + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.contentColorFor(backColor) + ) + } + } + } + } +} + +@Preview +@Composable +private fun HomePagePreview() { + CalculatorTheme { + HomePage( + modifier = Modifier.fillMaxSize(), + ) + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/a404m/calculator/ui/theme/Color.kt b/app/src/main/java/com/a404m/calculator/ui/theme/Color.kt new file mode 100644 index 0000000..6a4fd22 --- /dev/null +++ b/app/src/main/java/com/a404m/calculator/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.a404m.calculator.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)
\ No newline at end of file diff --git a/app/src/main/java/com/a404m/calculator/ui/theme/Theme.kt b/app/src/main/java/com/a404m/calculator/ui/theme/Theme.kt new file mode 100644 index 0000000..20d6120 --- /dev/null +++ b/app/src/main/java/com/a404m/calculator/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.a404m.calculator.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.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun CalculatorTheme( + 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 + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +}
\ No newline at end of file diff --git a/app/src/main/java/com/a404m/calculator/ui/theme/Type.kt b/app/src/main/java/com/a404m/calculator/ui/theme/Type.kt new file mode 100644 index 0000000..42ec494 --- /dev/null +++ b/app/src/main/java/com/a404m/calculator/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.a404m.calculator.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 + ) + */ +)
\ No newline at end of file diff --git a/app/src/main/java/com/a404m/calculator/ui/util/Container.kt b/app/src/main/java/com/a404m/calculator/ui/util/Container.kt new file mode 100644 index 0000000..ba27afe --- /dev/null +++ b/app/src/main/java/com/a404m/calculator/ui/util/Container.kt @@ -0,0 +1,31 @@ +package com.a404m.calculator.ui.util + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +fun <T> CalcGrid( + modifier: Modifier = Modifier, + columns: Int, + items: Array<T>, + builder: @Composable (T) -> Unit, +) { + Column( + modifier = modifier, + ) { + var index = 0 + while (index != items.size) { + Row { + for (j in 0 until columns) { + if(index == items.size){ + break + } + builder(items[index]) + ++index + } + } + } + } +}
\ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -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> diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..c5eec94 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,16 @@ +<?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="87" + android:viewportHeight="167.625"> + <group android:scaleX="0.23874721" + android:scaleY="0.46" + android:translateX="33.1145" + android:translateY="45.25875"> + <group android:translateY="133.66406"> + <path android:pathData="M6.1875,-36.84375L80.515625,-36.84375L80.515625,-24.75L6.1875,-24.75L6.1875,-36.84375ZM6.1875,-65.390625L80.515625,-65.390625L80.515625,-53.4375L6.1875,-53.4375L6.1875,-65.390625Z" + android:fillColor="#A437DB"/> + </group> + </group> +</vector>
\ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..7353dbd --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/ic_launcher_background"/> + <foreground android:drawable="@drawable/ic_launcher_foreground"/> +</adaptive-icon>
\ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..7353dbd --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@color/ic_launcher_background"/> + <foreground android:drawable="@drawable/ic_launcher_foreground"/> +</adaptive-icon>
\ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp Binary files differnew file mode 100644 index 0000000..ee62035 --- /dev/null +++ b/app/src/main/res/mipmap-hdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp Binary files differnew file mode 100644 index 0000000..6452b49 --- /dev/null +++ b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp Binary files differnew file mode 100644 index 0000000..8f60d53 --- /dev/null +++ b/app/src/main/res/mipmap-mdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp Binary files differnew file mode 100644 index 0000000..3cd3848 --- /dev/null +++ b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp Binary files differnew file mode 100644 index 0000000..9cb323b --- /dev/null +++ b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp Binary files differnew file mode 100644 index 0000000..6941df4 --- /dev/null +++ b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp Binary files differnew file mode 100644 index 0000000..eb514e1 --- /dev/null +++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp Binary files differnew file mode 100644 index 0000000..749d7c1 --- /dev/null +++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp Binary files differnew file mode 100644 index 0000000..e404ad0 --- /dev/null +++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp Binary files differnew file mode 100644 index 0000000..f7f408b --- /dev/null +++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -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>
\ No newline at end of file diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..3376515 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="ic_launcher_background">#35185A</color> +</resources>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..665ca8d --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> + <string name="app_name">Calculator</string> +</resources>
\ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..f244678 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <style name="Theme.Calculator" parent="android:Theme.Material.Light.NoActionBar" /> +</resources>
\ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000..fa0f996 --- /dev/null +++ b/app/src/main/res/xml/backup_rules.xml @@ -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>
\ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..9ee9997 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -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>
\ No newline at end of file diff --git a/app/src/test/java/com/a404m/calculator/ExampleUnitTest.kt b/app/src/test/java/com/a404m/calculator/ExampleUnitTest.kt new file mode 100644 index 0000000..4e8caf3 --- /dev/null +++ b/app/src/test/java/com/a404m/calculator/ExampleUnitTest.kt @@ -0,0 +1,20 @@ +package com.a404m.calculator + +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 + ) + } +}
\ No newline at end of file |