diff options
| author | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2024-12-18 03:28:02 +0330 | 
|---|---|---|
| committer | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2024-12-18 03:28:02 +0330 | 
| commit | d4573cacc141748c44bb6bbea7528bdd46afc3d5 (patch) | |
| tree | d5915bd32b2e58bae60ca906ec9475656c8a0e87 /app/src | |
initial commit
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  |