Feat(All): Tis

some changes
This commit is contained in:
Amir Mousavi
2026-05-06 23:33:56 +03:30
parent c9e656f705
commit d73df5524e
128 changed files with 1635 additions and 156 deletions
+12
View File
@@ -10,6 +10,18 @@
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DialogSelection /> <DialogSelection />
</SelectionState> </SelectionState>
<SelectionState runConfigName="practice.PSP.tis">
<option name="selectionMode" value="DROPDOWN" />
<DialogSelection />
</SelectionState>
<SelectionState runConfigName="tis_app">
<option name="selectionMode" value="DROPDOWN" />
<DialogSelection />
</SelectionState>
<SelectionState runConfigName="stage_app">
<option name="selectionMode" value="DROPDOWN" />
<DialogSelection />
</SelectionState>
</selectionStates> </selectionStates>
</component> </component>
</project> </project>
+3 -2
View File
@@ -12,9 +12,10 @@
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/core" /> <option value="$PROJECT_DIR$/core" />
<option value="$PROJECT_DIR$/design_system" /> <option value="$PROJECT_DIR$/design_system" />
<option value="$PROJECT_DIR$/ps3" /> <option value="$PROJECT_DIR$/p3" />
<option value="$PROJECT_DIR$/ps4" /> <option value="$PROJECT_DIR$/ps4" />
<option value="$PROJECT_DIR$/tis_sep" /> <option value="$PROJECT_DIR$/stage_app" />
<option value="$PROJECT_DIR$/tis_app" />
</set> </set>
</option> </option>
</GradleProjectSettings> </GradleProjectSettings>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PlanningModeManager">
<option name="approvalStates">
<map>
<entry key="20260504-162003-d0f92a5d-1a15-429a-82cc-cad6ed3c0e3e" value="true" />
</map>
</option>
</component>
</project>
@@ -0,0 +1,9 @@
package com.example.core.data
import com.example.core.domain.AppConfig
class AppConfigImpl : AppConfig{
override fun androidId(id: String): String {
return "window.WebV.onUUID($id);"
}
}
@@ -10,7 +10,7 @@ class PaymentResultImpl @Inject constructor(
) : PaymentResult { ) : PaymentResult {
override fun post(paymentResultEntity: PaymentResultEntity?): String { override fun post(paymentResultEntity: PaymentResultEntity?): String {
return "window.onPaymentResult(${gson.toJson(paymentResultEntity)});" return "window.WebV.onPaymentResult(${gson.toJson(paymentResultEntity)});"
} }
} }
@@ -1,6 +1,8 @@
package com.example.core.di package com.example.core.di
import com.example.core.data.AppConfigImpl
import com.example.core.data.PaymentResultImpl import com.example.core.data.PaymentResultImpl
import com.example.core.domain.AppConfig
import com.example.core.domain.PaymentResult import com.example.core.domain.PaymentResult
import com.google.gson.Gson import com.google.gson.Gson
import dagger.Module import dagger.Module
@@ -23,4 +25,9 @@ class CoreModule {
): PaymentResult = PaymentResultImpl( ): PaymentResult = PaymentResultImpl(
gson = gson gson = gson
) )
@Provides
fun provideAppConfig(
gson: Gson
): AppConfig = AppConfigImpl()
} }
@@ -0,0 +1,7 @@
package com.example.core.domain
import com.example.core.model.PaymentResultEntity
interface AppConfig {
fun androidId(id : String) : String
}
@@ -0,0 +1,11 @@
package com.example.core.domain
import androidx.annotation.DrawableRes
import com.example.core.model.PrintEntity
interface Printer {
fun print(
printEntities: List<PrintEntity>,
@DrawableRes icon :Int)
}
@@ -0,0 +1,23 @@
package com.example.core.model
import androidx.annotation.Keep
@Keep
data class PrintEntity(
val title: String? = null,
val items: List<ItemEntity>? = null,
val paragraph: String? = null,
val type: Type
) {
data class ItemEntity(
val label: String,
val value: String,
)
enum class Type() {
CARD,
PARAGRAPH
}
}
+28
View File
@@ -0,0 +1,28 @@
<!--
~ Copyright (C) 2026 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="200dp"
android:viewportWidth="800"
android:viewportHeight="200">
<path
android:pathData="M1.2,101.4L6.2,101.4L27.2,101.4L53.2,101.4L69.2,101.4L87.2,101.4L103.2,101.4L117.2,101.4L126.2,101.4L134.2,101.4L144.2,101.4L150.2,101.4L162.2,101.4L179.2,101.4L197.2,101.4L217.2,101.4L231.2,101.4L252.2,101.4L265.2,101.4L282.2,101.4L293.2,101.4L313.2,101.4L336.2,101.4L357.2,101.4L377.2,101.4L400.2,101.4L433.2,101.4L456.2,101.4L489.2,101.4L515.2,101.4L515.2,101.4L521.2,101.4L545.2,101.4L581.2,101.4L605.2,101.4L633.2,101.4L649.2,101.4L663.2,101.4L672.2,101.4L684.2,101.4L691.2,101.4L701.2,101.4L713.2,101.4L722.2,101.4L737.2,101.4L747.2,101.4L752.2,101.4L761.2,101.4L769.2,101.4L781.2,101.4L787.2,101.4L794.2,101.4L797.2,101.4L799.2,101.4L801.2,101.4"
android:strokeLineJoin="round"
android:strokeWidth="8"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
</vector>
@@ -0,0 +1,26 @@
<!--
~ Copyright (C) 2026 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="2dp"
android:viewportWidth="24.8"
android:viewportHeight="8">
<path
android:pathData="M0,0h24.8v248h-24.8z"
android:strokeWidth="0"
android:fillColor="#000000"
android:strokeColor="#000000"/>
</vector>
+3
View File
@@ -37,6 +37,7 @@ dependencies {
implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.retrofit.converter.gson)
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.compose.ui.test.junit4) androidTestImplementation(libs.androidx.compose.ui.test.junit4)
@@ -44,4 +45,6 @@ dependencies {
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
debugImplementation(libs.androidx.compose.ui.test.manifest) debugImplementation(libs.androidx.compose.ui.test.manifest)
debugImplementation(libs.androidx.compose.ui.tooling) debugImplementation(libs.androidx.compose.ui.tooling)
implementation(project(":core"))
} }
@@ -1,8 +1,10 @@
package com.example.design_system package com.example.design_system
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.JavascriptInterface import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebSettings import android.webkit.WebSettings
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
@@ -15,14 +17,17 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import com.example.core.model.PrintEntity
import com.example.design_system.util.PspJavaScriptInterface import com.example.design_system.util.PspJavaScriptInterface
import com.example.design_system.util.snackbar.SnackbarController import com.example.design_system.util.snackbar.SnackbarController
import com.example.design_system.util.snackbar.SnackbarEvent import com.example.design_system.util.snackbar.SnackbarEvent
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@SuppressLint("JavascriptInterface")
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun PspWebView( fun PspWebView(
@@ -31,7 +36,8 @@ fun PspWebView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onWebView: (WebView) -> Unit, onWebView: (WebView) -> Unit,
onPayClick: (amount: Long, id: String?) -> Unit, onPayClick: (amount: Long, id: String?) -> Unit,
onPrintClick: () -> Unit, onUUID: () -> Unit,
onPrintClick: (printEntities: List<PrintEntity>) -> Unit,
) { ) {
val canGoBack = remember { mutableStateOf(false) } val canGoBack = remember { mutableStateOf(false) }
@@ -40,6 +46,18 @@ fun PspWebView(
var lastBackTime by remember { mutableLongStateOf(0L) } var lastBackTime by remember { mutableLongStateOf(0L) }
var isPaymentLaunching by remember { mutableStateOf(false) } var isPaymentLaunching by remember { mutableStateOf(false) }
// Use rememberUpdatedState to ensure the bridge always calls the latest callbacks
val currentOnPayClick by rememberUpdatedState(onPayClick)
val currentOnPrintClick by rememberUpdatedState(onPrintClick)
val currentOnUUID by rememberUpdatedState(onUUID)
val bridge = remember {
PspJavaScriptInterface(
onPayClick = { amount, id -> currentOnPayClick(amount, id) },
onPrintClick = { entities -> currentOnPrintClick(entities) },
onUUID = { currentOnUUID() }
)
}
BackHandler { BackHandler {
if (canGoBack.value) { if (canGoBack.value) {
@@ -61,7 +79,6 @@ fun PspWebView(
} }
} }
AndroidView( AndroidView(
modifier = modifier, modifier = modifier,
factory = { ctx -> factory = { ctx ->
@@ -89,23 +106,7 @@ fun PspWebView(
"Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 Chrome/120.0 Mobile Safari/537.36" "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 Chrome/120.0 Mobile Safari/537.36"
} }
addJavascriptInterface( addJavascriptInterface(bridge, "NativeBridge")
object : PspJavaScriptInterface {
@JavascriptInterface
override fun pay(amount: Long, id: String?) {
onPayClick(amount, id)
}
@JavascriptInterface
override fun print(text: String) {
TODO("Not yet implemented")
}
}, "AndroidPSP"
)
loadUrl(url) loadUrl(url)
@@ -1,8 +1,51 @@
package com.example.design_system.util package com.example.design_system.util
interface PspJavaScriptInterface { import android.util.Log
import android.webkit.JavascriptInterface
import androidx.annotation.Keep
import com.example.core.model.PrintEntity
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
fun pay(amount: Long,id: String?) @Keep
class PspJavaScriptInterface(
private val onPayClick: (Long, String?) -> Unit,
private val onPrintClick: (List<PrintEntity>) -> Unit,
private val onUUID: () -> Unit,
) {
fun print(text: String) @JavascriptInterface
} @Keep
fun pay(amount: Double, id: String?) {
Log.d("PspBridge", "pay called: amount=$amount, id=$id")
try {
onPayClick(amount.toLong(), id)
} catch (e: Exception) {
Log.e("PspBridge", "Error in pay callback", e)
}
}
@JavascriptInterface
@Keep
fun print(printEntitiesJson: String) {
Log.d("PspBridge", "print called: $printEntitiesJson")
try {
val type = object : TypeToken<List<PrintEntity>>() {}.type
val list: List<PrintEntity> = Gson().fromJson(printEntitiesJson, type)
onPrintClick(list)
} catch (e: Exception) {
Log.e("PspBridge", "Error parsing print entities", e)
}
}
@JavascriptInterface
@Keep
fun uuid() {
Log.d("PspBridge", "uuid called")
try {
onUUID()
} catch (e: Exception) {
Log.e("PspBridge", "Error in uuid callback", e)
}
}
}
View File
+16 -14
View File
@@ -5,24 +5,29 @@ plugins {
} }
android { android {
namespace = "com.example.ps3" namespace = "com.example.p3"
compileSdk { compileSdk = 36
version = release(36) {
minorApiLevel = 1
}
}
defaultConfig { defaultConfig {
minSdk = 24 minSdk = 24
// targetSdk is often not needed for library modules
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro") consumerProguardFiles("consumer-rules.pro")
} }
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
} }
dependencies { dependencies {
@@ -39,10 +44,7 @@ dependencies {
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
// implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) // Using implementation to bundle the JAR and avoid NoClassDefFoundError
implementation(files("libs/platform_sdk_v2.3.706.jar"))
implementation(files("libs/classes-2.1.17.jar"))
// 2. This specifically includes the platform SDK jar
compileOnly(files("libs/platform_sdk_v2.3.706.jar"))
} }
Binary file not shown.
View File
@@ -1,4 +1,4 @@
package com.example.ps3 package com.example.p3
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -1,4 +1,4 @@
package com.example.ps3 package com.example.p3
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -6,7 +6,7 @@ import android.content.pm.PackageManager
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import com.example.core.model.PaymentResultEntity import com.example.core.model.PaymentResultEntity
import com.example.core.model.PaymentResultStatus import com.example.core.model.PaymentResultStatus
import com.example.ps3.models.IapAccountSplit import com.example.p3.models.IapAccountSplit
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import javax.inject.Inject import javax.inject.Inject
@@ -0,0 +1,333 @@
package com.example.p3
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.util.Log
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.core.graphics.createBitmap
import com.example.core.domain.Printer
import com.example.core.model.PrintEntity
import com.pos.sdk.printer.POIPrinterManager
import com.pos.sdk.printer.POIPrinterManager.IPrinterListener
import com.pos.sdk.printer.models.BitmapPrintLine
import com.pos.sdk.printer.models.PrintLine
import com.pos.sdk.printer.models.TextPrintLine
import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.File
import javax.inject.Inject
class P3Printer @Inject constructor(
@param:ApplicationContext private val context: Context,
) : Printer {
companion object {
private const val TAG = "Printer"
// Printer state constants (should ideally come from the SDK if available)
private const val PRINTER_STATE_ERROR = 4
private const val DEFAULT_PRINT_GRAY = 2000
private const val DEFAULT_LINE_SPACE = 5
}
/**
* Prints a sample receipt for demonstration.
*/
fun printSampleReceipt(context: Context) {
// Use applicationContext to avoid potential memory leaks
val printerManager = initialP3Printer()
printerManager?.apply {
setPrintGray(DEFAULT_PRINT_GRAY)
setLineSpace(DEFAULT_LINE_SPACE)
// Header
addPrintLine(TextPrintLine("This is an example of a receipt", PrintLine.CENTER))
// Reusable logo bitmap
val logoBitmap = drawableToBitmap(context, android.R.drawable.btn_plus)
val logoLine = logoBitmap?.let { BitmapPrintLine(it, PrintLine.CENTER) }
logoLine?.let { addPrintLine(it) }
// Address
val addressFont = getFontPath("font")
if (addressFont.isNotEmpty()) {
setPrintFont(addressFont)
} else {
setPrintFont("/system/fonts/ComingSoon.ttf")
}
addPrintLine(
TextPrintLine(
"Floor ** , Building **, No.*** LONG DONG Avenue, Pudong New District, Shanghai, China",
PrintLine.LEFT,
20
)
)
// Transaction Details
val detailFont = getFontPath("font")
if (detailFont.isNotEmpty()) {
setPrintFont(detailFont)
} else {
setPrintFont("/system/fonts/DroidSansMono.ttf")
}
// addPrintLine(createPrintRow("24 June 2025", " Assistant 6", "815002", size = 18))
// addPrintLine(createPrintRow("Item", "Quantity", "Price", size = 24, isBold = true))
// addPrintLine(createPrintRow("Tomato", "1", "$2.08", size = 24))
// addPrintLine(createPrintRow("Orange", "1", "$1.06", size = 24))
//
// Footer
addPrintLine(TextPrintLine("Total $3.14", PrintLine.RIGHT))
addPrintLine(TextPrintLine(""))
logoLine?.let { addPrintLine(it) }
addPrintLine(TextPrintLine(""))
addPrintLine(
TextPrintLine(
"Did you know you could have earned Rewards points on this purchase?",
PrintLine.CENTER
)
)
addPrintLine(
TextPrintLine(
"Simply sign up today for a Membership Card!",
PrintLine.CENTER
)
)
logoLine?.let { addPrintLine(it) }
addPrintLine(TextPrintLine(" ", 0, 100))
val listener = object : IPrinterListener {
override fun onStart() {
Log.d(TAG, "Print started")
}
override fun onFinish() {
Log.d(TAG, "Print finished")
close()
}
override fun onError(code: Int, msg: String?) {
Log.e(TAG, "Print error - code: $code, message: $msg")
close()
}
}
beginPrint(listener)
}
}
private fun initialP3Printer(): POIPrinterManager? {
val printerManager = POIPrinterManager(context.applicationContext)
printerManager.open()
val state = printerManager.printerState
Log.d(TAG, "Printer state = $state")
if (state == PRINTER_STATE_ERROR) {
Log.e(TAG, "Printer is in an error state ($state). Aborting print.")
printerManager.close()
return null
}
return printerManager
}
/**
* Creates a row with left, center, and right aligned text.
*/
private fun createPrintRow(
label: String,
value: String,
size: Int,
isBold: Boolean = false
): List<TextPrintLine> {
return if (value.hasPersianLetters()) {
listOf(
TextPrintLine(label, PrintLine.LEFT, size, true),
TextPrintLine(value, PrintLine.RIGHT, size, isBold)
)
} else {
listOf(
TextPrintLine(label, PrintLine.LEFT, size, true),
TextPrintLine(value, PrintLine.LEFT, size, isBold)
)
}
}
private fun getFontPath(resourceName: String): String {
return try {
// Find resource ID by name (e.g., "font") in the "font" resource folder
val resId = context.resources.getIdentifier(resourceName, "font", context.packageName)
if (resId == 0) {
Log.e(TAG, "Font resource not found: $resourceName")
return ""
}
val fileName = "$resourceName.ttf"
val fontFile = File(context.filesDir, fileName)
if (!fontFile.exists()) {
context.resources.openRawResource(resId).use { input ->
fontFile.outputStream().use { output ->
input.copyTo(output)
}
}
}
fontFile.absolutePath
} catch (e: Exception) {
Log.e(TAG, "Error loading font from resources: $resourceName", e)
""
}
}
override fun print(
printEntities: List<PrintEntity>,
@DrawableRes icon: Int
) {
val printerManager = initialP3Printer()
printerManager?.apply {
setPrintGray(DEFAULT_PRINT_GRAY)
setLineSpace(DEFAULT_LINE_SPACE)
// Reusable logo bitmap
val logoBitmap = drawableToBitmap(context, icon, 200)
if (logoBitmap != null) {
val logoLine = BitmapPrintLine(logoBitmap, PrintLine.CENTER)
addPrintLine(logoLine)
addPrintLine(TextPrintLine(" ", 0, 10))
}
val customFontPath = getFontPath("font")
if (customFontPath.isNotEmpty()) {
setPrintFont(customFontPath)
} else {
setPrintFont("/system/fonts/DroidSansMono.ttf") // Fallback
}
val divider = drawableToBitmap(context, com.example.core.R.drawable.horizontal_line_svgrepo_com__1_)
printEntities.forEachIndexed { index, printEntity ->
// Header
printEntity.title?.let {title->
addPrintLine(
TextPrintLine(
title,
if (title.hasPersianLetters()) PrintLine.LEFT else PrintLine.RIGHT
)
)
}
printEntity.items?.let {items->
items.forEach { itemEntity ->
addPrintLine(
createPrintRow(
label = itemEntity.label,
value = itemEntity.value,
size = 16,
)
)
}
}
if (divider != null && printEntities.lastIndex > index) {
val dividerLine = BitmapPrintLine(divider, PrintLine.CENTER)
addPrintLine(dividerLine)
}
}
addPrintLine(TextPrintLine(" ", 0, 60))
val listener = object : IPrinterListener {
override fun onStart() {
Log.d(TAG, "Print started")
}
override fun onFinish() {
Log.d(TAG, "Print finished")
close()
}
override fun onError(code: Int, msg: String?) {
Log.e(TAG, "Print error - code: $code, message: $msg")
close()
}
}
beginPrint(listener)
}
}
// private fun fixForPrinter(input: String): String {
// val LRM = '\u200E' // کنترل جهت
//
// return input
// .toPersianDigits() // همونی که قبل دادم
// .replace(Regex("(\\d+)")) { matchResult ->
// "$LRM${matchResult.value}$LRM"
// }
// }
private fun String.hasPersianLetters(): Boolean {
return Regex("[\\u0621-\\u0628\\u062A-\\u063A\\u0641-\\u0642\\u0644-\\u0648\\u067E\\u0686\\u0698\\u06A9\\u06AF\\u06CC\\u0647]").containsMatchIn(
this
)
}
private fun drawableToBitmap(context: Context, @DrawableRes drawableId: Int): Bitmap? {
val drawable = ContextCompat.getDrawable(context, drawableId) ?: return null
if (drawable is BitmapDrawable) {
return drawable.bitmap
}
val bitmap = createBitmap(
drawable.intrinsicWidth.coerceAtLeast(1),
drawable.intrinsicHeight.coerceAtLeast(1)
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
private fun drawableToBitmap(
context: Context,
@DrawableRes drawableId: Int,
maxWidth: Int = 300
): Bitmap? {
val drawable = ContextCompat.getDrawable(context, drawableId) ?: return null
val original = if (drawable is BitmapDrawable) {
drawable.bitmap
} else {
val bitmap = createBitmap(
drawable.intrinsicWidth.coerceAtLeast(1),
drawable.intrinsicHeight.coerceAtLeast(1)
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
bitmap
}
// 👇 scale با حفظ نسبت
val ratio = maxWidth.toFloat() / original.width
val width = maxWidth
val height = (original.height * ratio).toInt()
return Bitmap.createScaledBitmap(original, width, height, true)
}
}
@@ -1,4 +1,4 @@
package com.example.ps3 package com.example.p3
import android.content.Intent import android.content.Intent
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
@@ -8,7 +8,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import javax.inject.Inject import javax.inject.Inject
class Ps3Service @Inject constructor( class P3Service @Inject constructor(
private val iapPosService: IapPosService, private val iapPosService: IapPosService,
private val printerHelper: PrinterHelper private val printerHelper: PrinterHelper
) : PspService { ) : PspService {
@@ -21,9 +21,8 @@ class Ps3Service @Inject constructor(
} }
override fun print(lines: List<String>, onMessage: (String) -> Unit) { override fun print(lines: List<String>, onMessage: (String) -> Unit) {
// printerHelper.printText()
printerHelper.printLines(lines) { status -> printerHelper.printLines(lines) { status ->
onMessage("PS3 Printer: $status") onMessage("P3 Printer: $status")
} }
} }
@@ -1,4 +1,4 @@
package com.example.ps3 package com.example.p3
import android.device.PrinterManager import android.device.PrinterManager
import android.graphics.Bitmap import android.graphics.Bitmap
@@ -1,7 +1,7 @@
package com.example.ps3.di package com.example.p3.di
import android.content.Context import android.content.Context
import com.example.ps3.IapPosService import com.example.p3.IapPosService
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@@ -11,7 +11,7 @@ import javax.inject.Singleton
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
object Ps3Module { object P3Module {
@Provides @Provides
@Singleton @Singleton
@@ -1,4 +1,4 @@
package com.example.ps3.models package com.example.p3.models
data class IapAccountSplit( data class IapAccountSplit(
val index: Int, val index: Int,
Binary file not shown.
@@ -1,4 +1,4 @@
package com.example.ps3 package com.example.p3
import org.junit.Test import org.junit.Test
@@ -0,0 +1,20 @@
package com.example.ps4
import android.content.Context
import androidx.annotation.DrawableRes
import com.example.core.domain.Printer
import com.example.core.model.PrintEntity
import javax.inject.Inject
class P4Printer @Inject constructor(
private val context: Context,
) : Printer {
override fun print(
printEntities: List<PrintEntity>,
@DrawableRes icon: Int
) {
}
}
+3 -2
View File
@@ -24,8 +24,9 @@ dependencyResolutionManagement {
rootProject.name = "PSP" rootProject.name = "PSP"
include(":app") include(":app")
include(":tis_sep") include(":tis_app")
include(":ps3") include(":p3")
include(":ps4") include(":ps4")
include(":core") include(":core")
include(":design_system") include(":design_system")
include(":stage_app")
+85
View File
@@ -0,0 +1,85 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.ksp)
alias(libs.plugins.hilt)}
android {
namespace = "com.example.stage_app"
compileSdk {
version = release(36) {
minorApiLevel = 1
}
}
defaultConfig {
applicationId = "com.example.stage_app"
minSdk = 24
targetSdk = 36
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
flavorDimensions.add("module")
productFlavors {
create("p3") {
dimension = "module"
}
create("ps4") {
dimension = "module"
}
create("standard") {
dimension = "module"
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
buildFeatures {
compose = true
buildConfig = true
}
}
dependencies {
implementation(project(":core"))
implementation(project(":design_system"))
"p3Implementation"(project(":p3"))
"ps4Implementation"(project(":ps4"))
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
testImplementation(libs.junit)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(libs.androidx.junit)
debugImplementation(libs.androidx.compose.ui.test.manifest)
debugImplementation(libs.androidx.compose.ui.tooling)
}
@@ -0,0 +1,24 @@
package com.example.stage_app
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.example.stage_app", appContext.packageName)
}
}
+42
View File
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT" />
<data android:mimeType="text/plain" />
</intent>
<package android:name="ir.co.pna.pos" />
<intent>
<action android:name="ir.co.pna.pos.view.cart.IAPCActivity" />
</intent>
</queries>
<uses-permission android:name="android.permission.PRINTER" />
<uses-permission android:name="com.pos.permission.PRINTER" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".PspApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PSP"
android:usesCleartextTraffic="true">
<uses-library android:name="android.device" android:required="false" />
<activity
android:name=".StageMainActivity"
android:exported="true"
android:theme="@style/Theme.PSP">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,7 @@
package com.example.stage_app
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class PspApplication : Application()
@@ -0,0 +1,69 @@
package com.example.stage_app
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import com.example.design_system.theme.tis.TisTheme
import com.example.design_system.util.ObserveAsEvents
import com.example.design_system.util.snackbar.SnackbarController
import com.example.stage_app.screen.StageWebViewScreen
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
@AndroidEntryPoint
class StageMainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TisTheme {
val scope = rememberCoroutineScope()
val snackbarHostState = remember {
SnackbarHostState()
}
ObserveAsEvents(
flow = SnackbarController.events,
snackbarHostState
) { event ->
scope.launch {
snackbarHostState.currentSnackbarData?.dismiss()
val result = snackbarHostState.showSnackbar(
message = event.message,
actionLabel = event.action?.name,
duration = event.duration
)
if (result == SnackbarResult.ActionPerformed) {
event.action?.action?.invoke()
}
}
}
Scaffold(
snackbarHost = {
SnackbarHost(
hostState = snackbarHostState
)
}
) { paddingValues ->
StageWebViewScreen(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
)
}
}
}
}
}
@@ -0,0 +1,73 @@
package com.example.stage_app.screen
import android.provider.Settings
import android.webkit.WebView
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.design_system.PspWebView
import com.example.stage_app.viewmodel.StageViewModel
private const val tisIp = "192.168.128.73:5000"
@Composable
fun StageWebViewScreen(
modifier: Modifier = Modifier,
viewModel: StageViewModel = hiltViewModel()
) {
val context = LocalContext.current
var webView: WebView? by remember { mutableStateOf(null) }
var currentPaymentId by rememberSaveable { mutableStateOf<String?>(null) }
// launcher to handle POS app result
val posLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { result ->
val paymentResultEntity = viewModel.paymentResult(
id = currentPaymentId,
activityResult = result
)
webView?.post {
webView?.evaluateJavascript(
viewModel.postPaymentResult(paymentResultEntity = paymentResultEntity),
null
)
}
}
PspWebView(
url = tisIp,
webView = webView,
modifier = modifier,
onWebView = { updatedWebView -> webView = updatedWebView },
onPayClick = { amount: Long, id: String? ->
currentPaymentId = id
viewModel.pay(amount)
.also(posLauncher::launch)
},
onPrintClick = { printEntities ->
viewModel.print(printEntities)
},
onUUID = {
val androidId = Settings
.Secure
.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
viewModel.sendAndroidId(
androidId
)
}
)
}
@@ -0,0 +1,72 @@
package com.example.stage_app.viewmodel
import android.content.Intent
import androidx.activity.result.ActivityResult
import androidx.lifecycle.ViewModel
import com.example.core.domain.AppConfig
import com.example.core.domain.PaymentResult
import com.example.core.domain.Printer
import com.example.core.domain.PspService
import com.example.core.model.PaymentResultEntity
import com.example.core.model.PrintEntity
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class StageViewModel @Inject constructor(
private val pspService: PspService,
private val paymentResult: PaymentResult,
private val printer: Printer,
private val appConfig: AppConfig
) : ViewModel() {
fun postPaymentResult(paymentResultEntity: PaymentResultEntity?): String {
return paymentResult.post(paymentResultEntity)
}
fun pay(amount: Long): Intent = pspService.pay(amount)
fun paymentResult(
id: String?,
activityResult: ActivityResult
): PaymentResultEntity? {
return pspService.decodePosResponse(
id = id,
activityResult = activityResult
)
}
private val mock = listOf<PrintEntity>(
PrintEntity(
title = "اطلاعات مشتری",
items = listOf(
PrintEntity.ItemEntity("نام مشتری", "علی رضایی"),
PrintEntity.ItemEntity("شماره تماس", "09123456789"),
PrintEntity.ItemEntity("آدرس", "تهران، خیابان ولیعصر، پلاک ۱۲۳")
),
type = PrintEntity.Type.CARD
),
PrintEntity(
title = "اطلاعات پرداخت",
items = listOf(
PrintEntity.ItemEntity("روش پرداخت", "کارت به کارت"),
PrintEntity.ItemEntity("شماره پیگیری", "7845129630"),
PrintEntity.ItemEntity("تاریخ", "1405/02/14")
),
type = PrintEntity.Type.CARD
),
)
fun print(printEntities: List<PrintEntity>) {
printer.print(
printEntities = printEntities,
icon = android.R.drawable.btn_star
)
}
fun sendAndroidId(id: String) {
appConfig.androidId(id)
}
}
@@ -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>
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

@@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.PSP" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">stage_app</string>
</resources>
+16
View File
@@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.PSP" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
@@ -0,0 +1,20 @@
package com.example.tis_app.di
import com.example.core.domain.Printer
import com.example.core.domain.PspService
import com.example.p3.P3Printer
import com.example.p3.P3Service
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
abstract class PspModule {
@Binds
abstract fun bindPspService(impl: P3Service): PspService
@Binds
abstract fun bindPrinter(impl: P3Printer): Printer
}
@@ -2,6 +2,7 @@ package com.example.tis_sep.di
import com.example.core.PspService import com.example.core.PspService
import com.example.ps4.Ps4Service import com.example.ps4.Ps4Service
import com.example.ps4.P4Printer
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@@ -12,4 +13,8 @@ import dagger.hilt.components.SingletonComponent
abstract class PspModule { abstract class PspModule {
@Binds @Binds
abstract fun bindPspService(impl: Ps4Service): PspService abstract fun bindPspService(impl: Ps4Service): PspService
@Binds
abstract fun bindPrinter(impl: P4Printer): Printer
} }
@@ -0,0 +1,17 @@
package com.example.stage_app
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)
}
}
+1
View File
@@ -0,0 +1 @@
/build
@@ -6,7 +6,7 @@ plugins {
} }
android { android {
namespace = "com.example.tis_sep" namespace = "com.example.tis_app"
compileSdk { compileSdk {
version = release(36) { version = release(36) {
minorApiLevel = 1 minorApiLevel = 1
@@ -14,7 +14,7 @@ android {
} }
defaultConfig { defaultConfig {
applicationId = "com.example.tis_sep" applicationId = "com.example.tis_app"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode = 1 versionCode = 1
@@ -25,7 +25,7 @@ android {
flavorDimensions.add("module") flavorDimensions.add("module")
productFlavors { productFlavors {
create("ps3") { create("p3") {
dimension = "module" dimension = "module"
} }
create("ps4") { create("ps4") {
@@ -58,11 +58,7 @@ android {
dependencies { dependencies {
implementation(project(":core")) implementation(project(":core"))
implementation(project(":design_system")) implementation(project(":design_system"))
"ps3Implementation"(project(":ps3")) "p3Implementation"(project(":p3"))
"ps3CompileOnly"(files("../ps3/libs/platform_sdk_v2.3.706.jar"))
// Provide the library for compilation only in the ps3 flavor
// "ps3CompileOnly"(files("${rootProject.projectDir}/external_sdks/platform_sdk_v2.3.706.jar"))
"ps4Implementation"(project(":ps4")) "ps4Implementation"(project(":ps4"))
+21
View File
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
@@ -1,4 +1,4 @@
package com.example.tis_sep package com.example.tis_app
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@@ -1,4 +1,4 @@
package com.example.tis_sep package com.example.tis_app
import android.app.Application import android.app.Application
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
@@ -1,4 +1,4 @@
package com.example.tis_sep package com.example.tis_app
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
@@ -15,7 +15,7 @@ import androidx.compose.ui.Modifier
import com.example.design_system.theme.tis.TisTheme import com.example.design_system.theme.tis.TisTheme
import com.example.design_system.util.ObserveAsEvents import com.example.design_system.util.ObserveAsEvents
import com.example.design_system.util.snackbar.SnackbarController import com.example.design_system.util.snackbar.SnackbarController
import com.example.tis_sep.screen.TisWebViewScreen import com.example.tis_app.screen.TisWebViewScreen
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -55,6 +55,8 @@ class TisMainActivity : ComponentActivity() {
) )
} }
) { paddingValues -> ) { paddingValues ->
TisWebViewScreen( TisWebViewScreen(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -1,5 +1,6 @@
package com.example.tis_sep.screen package com.example.tis_app.screen
import android.provider.Settings
import android.webkit.WebView import android.webkit.WebView
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
@@ -10,16 +11,18 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.example.design_system.PspWebView import com.example.design_system.PspWebView
import com.example.tis_sep.viewmodel.WebViewModel import com.example.tis_app.viewmodel.WebViewModel
private const val tisIp = "194.59.214.243:8090"
@Composable @Composable
fun TisWebViewScreen( fun TisWebViewScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: WebViewModel = hiltViewModel() viewModel: WebViewModel = hiltViewModel()
) { ) {
val context = LocalContext.current
var webView: WebView? by remember { mutableStateOf(null) } var webView: WebView? by remember { mutableStateOf(null) }
var currentPaymentId by rememberSaveable { mutableStateOf<String?>(null) } var currentPaymentId by rememberSaveable { mutableStateOf<String?>(null) }
@@ -42,7 +45,7 @@ fun TisWebViewScreen(
} }
PspWebView( PspWebView(
url = "192.168.128.73:5000", url = tisIp,
webView = webView, webView = webView,
modifier = modifier, modifier = modifier,
onWebView = { updatedWebView -> webView = updatedWebView }, onWebView = { updatedWebView -> webView = updatedWebView },
@@ -51,6 +54,18 @@ fun TisWebViewScreen(
viewModel.pay(amount) viewModel.pay(amount)
.also(posLauncher::launch) .also(posLauncher::launch)
}, },
onPrintClick = {}, onPrintClick = { printEntities ->
viewModel.print(printEntities)
},
onUUID = {
val androidId = Settings
.Secure
.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
viewModel.sendAndroidId(
androidId
)
}
) )
} }
@@ -1,18 +1,24 @@
package com.example.tis_sep.viewmodel package com.example.tis_app.viewmodel
import android.content.Intent import android.content.Intent
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.example.core.domain.AppConfig
import com.example.core.domain.PaymentResult import com.example.core.domain.PaymentResult
import com.example.core.domain.Printer
import com.example.core.domain.PspService import com.example.core.domain.PspService
import com.example.core.model.PaymentResultEntity import com.example.core.model.PaymentResultEntity
import com.example.core.model.PrintEntity
import com.example.tis_app.R
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class WebViewModel @Inject constructor( class WebViewModel @Inject constructor(
private val pspService: PspService, private val pspService: PspService,
private val paymentResult: PaymentResult private val paymentResult: PaymentResult,
private val printer: Printer,
private val appConfig: AppConfig
) : ViewModel() { ) : ViewModel() {
@@ -31,4 +37,14 @@ class WebViewModel @Inject constructor(
activityResult = activityResult activityResult = activityResult
) )
} }
fun print(printEntities : List<PrintEntity>) {
printer.print(
printEntities = printEntities,
icon = R.drawable.tis_icon
)
}
fun sendAndroidId(id : String) {
appConfig.androidId(id)
}
} }
@@ -0,0 +1,20 @@
<!--
~ Copyright (C) 2026 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="#FF000000" android:pathData="M17.6,11.48 L19.44,8.3a0.63,0.63 0,0 0,-1.09 -0.63l-1.88,3.24a11.43,11.43 0,0 0,-8.94 0L5.65,7.67a0.63,0.63 0,0 0,-1.09 0.63L6.4,11.48A10.81,10.81 0,0 0,1 20L23,20A10.81,10.81 0,0 0,17.6 11.48ZM7,17.25A1.25,1.25 0,1 1,8.25 16,1.25 1.25,0 0,1 7,17.25ZM17,17.25A1.25,1.25 0,1 1,18.25 16,1.25 1.25,0 0,1 17,17.25Z"/>
</vector>
@@ -0,0 +1,78 @@
<?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">
<group android:scaleX="1.42"
android:scaleY="1.42"
android:translateX="-22.68"
android:translateY="-22.68">
<path android:fillColor="#FFFFFF"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#FFFFFF" android:pathData="M9,0L9,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M19,0L19,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M29,0L29,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M39,0L39,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M49,0L49,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M59,0L59,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M69,0L69,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M79,0L79,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M89,0L89,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M99,0L99,108"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,9L108,9"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,19L108,19"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,29L108,29"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,39L108,39"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,49L108,49"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,59L108,59"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,69L108,69"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,79L108,79"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,89L108,89"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M0,99L108,99"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M19,29L89,29"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M19,39L89,39"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M19,49L89,49"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M19,59L89,59"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M19,69L89,69"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M19,79L89,79"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M29,19L29,89"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M39,19L39,89"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M49,19L49,89"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M59,19L59,89"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M69,19L69,89"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#FFFFFF" android:pathData="M79,19L79,89"
android:strokeColor="#FFFFFF" android:strokeWidth="0.8"/>
</group>
</vector>
+144
View File
@@ -0,0 +1,144 @@
<!--
~ Copyright (C) 2026 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="237dp"
android:height="68dp"
android:viewportWidth="237"
android:viewportHeight="68">
<path
android:pathData="M28.5,22.75C32,23 32,23 34,25C34.29,26.85 34.29,26.85 34.34,29.06C34.37,29.86 34.4,30.66 34.43,31.48C34.48,33.16 34.52,34.84 34.57,36.52C34.6,37.32 34.63,38.12 34.66,38.94C34.68,40.03 34.68,40.03 34.71,41.15C34.85,43.25 34.85,43.25 37,45C40.31,41.69 39.4,36.71 39.48,32.21C39.68,26.41 39.68,26.41 41.34,24.28C43,23 43,23 46,22.56C49,23 49,23 50.68,24.45C52.68,28.32 52.32,31.96 52.19,36.25C52.17,37.51 52.17,37.51 52.15,38.8C52.11,40.86 52.06,42.93 52,45C53.32,44.67 54.64,44.34 56,44C56.01,43.43 56.03,42.87 56.04,42.29C56.12,39.73 56.22,37.18 56.31,34.63C56.34,33.74 56.36,32.85 56.38,31.93C56.42,31.08 56.45,30.23 56.49,29.35C56.51,28.57 56.54,27.78 56.57,26.97C57,25 57,25 60,23C63.06,22.75 63.06,22.75 66,23C68.44,25.44 68.29,26.21 68.41,29.57C68.47,30.78 68.47,30.78 68.52,32.02C68.56,33.04 68.59,34.07 68.63,35.13C68.75,38.38 68.87,41.64 69,45C81.38,44.5 81.38,44.5 94,44C94.21,38.21 94.21,38.21 94.39,32.42C94.44,31.34 94.44,31.34 94.49,30.23C94.53,29.12 94.53,29.12 94.57,27.99C95.11,25.49 96,24.56 98,23C100.82,22.85 103.2,23.46 106,24C107.51,25.51 107.2,26.89 107.28,29C107.34,30.21 107.34,30.21 107.39,31.44C107.46,33.15 107.54,34.85 107.61,36.56C107.66,37.77 107.66,37.77 107.72,39C107.75,39.74 107.78,40.49 107.81,41.25C107.82,43.03 107.82,43.03 109,44C111.38,44.09 113.72,44.12 116.1,44.1C116.81,44.1 117.52,44.09 118.25,44.09C120.52,44.09 122.79,44.08 125.06,44.06C126.6,44.06 128.14,44.05 129.67,44.05C133.45,44.04 137.22,44.02 141,44C142.12,41.76 142.19,40.35 142.32,37.87C142.36,37.06 142.4,36.26 142.44,35.43C142.48,34.58 142.52,33.74 142.56,32.88C142.63,31.6 142.63,31.6 142.69,30.3C142.8,28.2 142.9,26.1 143,24C146.01,22.49 148.68,22.82 152,23C155.33,26.33 154.37,30.67 154.38,35.19C154.4,36.12 154.42,37.06 154.45,38.02C154.48,44.23 153.79,48.01 150,53C145.51,56.61 141.37,56.42 135.87,56.36C134.56,56.36 134.56,56.36 133.22,56.36C131.38,56.36 129.54,56.35 127.7,56.34C124.88,56.31 122.06,56.32 119.24,56.32C117.45,56.32 115.66,56.31 113.87,56.3C113.02,56.3 112.18,56.3 111.31,56.3C107.38,56.26 105.35,56.23 102,54C101.49,54.33 100.98,54.65 100.45,54.99C97.13,56.36 94.34,56.24 90.75,56.23C90.05,56.23 89.36,56.23 88.64,56.23C87.18,56.23 85.71,56.22 84.25,56.21C82.01,56.19 79.77,56.19 77.53,56.19C66.49,56.15 66.49,56.15 62,55C61.01,55.49 61.01,55.49 60,56C58.21,56.1 56.42,56.13 54.63,56.13C53.67,56.13 52.71,56.13 51.73,56.13C49,56 49,56 46.77,55.43C44.91,54.78 44.91,54.78 43,56C40.7,56.23 38.4,56.38 36.09,56.52C33.61,56.84 33.61,56.84 32,60C31.34,60 30.68,60 30,60C29.67,60.99 29.34,61.98 29,63C24.4,65.77 19.14,65.37 13.94,65.38C12.59,65.41 12.59,65.41 11.22,65.45C4.68,65.48 4.68,65.48 1.38,63.14C0,61 0,61 0.06,58.38C1,56 1,56 4,54C6.71,53.72 9.35,53.54 12.06,53.44C17.19,53.43 17.19,53.43 22,52C22.02,51.19 22.04,50.39 22.06,49.55C22.16,45.91 22.26,42.27 22.38,38.63C22.42,36.72 22.42,36.72 22.47,34.77C22.51,33.56 22.55,32.35 22.59,31.1C22.62,29.98 22.65,28.86 22.68,27.71C23.18,23.44 24.29,23.05 28.5,22.75Z"
android:fillColor="#0A774D"/>
<path
android:pathData="M184,0C186.89,-0.12 188.37,-0.09 191,1C194.04,4.06 196.47,7.52 199,11C202.48,15.62 202.48,15.62 207,19C207,19.99 207,20.98 207,22C207.99,22.33 208.98,22.66 210,23C211.87,25.07 211.87,25.07 213.88,27.69C216.17,30.67 218.47,33.52 221.06,36.25C223,39 223,39 223.13,42.06C221.72,45.72 220.03,47.54 217,50C214.69,50.81 214.69,50.81 213,51C213.1,51.72 213.21,52.44 213.31,53.19C212.87,57.17 211.01,58.48 208,61C206.51,61.49 206.51,61.49 205,62C203.77,65.01 203.77,65.01 203,68C199.37,68 195.74,68 192,68C194.03,63.95 195.89,61.05 200,59C201.01,57.25 202.01,55.49 202.99,53.72C204.12,51.79 205.19,50.34 207,49C207.99,49 208.98,49 210,49C210.62,45.56 211,42.51 211,39C209.71,37.09 209.71,37.09 208,35.38C205,32.19 205,32.19 205,30C204.34,30 203.68,30 203,30C201.77,28.31 200.55,26.61 199.37,24.88C197.89,22.75 197.89,22.75 195.25,20.25C193,18 193,18 192,15C191.34,15 190.68,15 190,15C187.27,12.27 184.97,9.32 183,6C183.06,2.44 183.06,2.44 184,0Z"
android:fillColor="#11754D"/>
<path
android:pathData="M201,0C203.63,0.38 203.63,0.38 206,1C206.33,1.99 206.66,2.98 207,4C207.66,4 208.32,4 209,4C209.34,5.39 209.34,5.39 209.69,6.81C211.25,10.62 212.51,11.04 216,13C217.02,14.65 218.03,16.32 219,18C219.99,18.33 220.98,18.66 222,19C227,24.47 227,24.47 227,27C227.66,27 228.32,27 229,27C233,31.47 233,31.47 233,34C234.32,34.66 235.64,35.32 237,36C237.49,43.22 237.49,43.22 235.13,47C233,49 233,49 231,49C230.77,49.7 230.55,50.39 230.32,51.11C228.71,54.63 226.46,57.31 223.94,60.19C220.63,63.86 220.63,63.86 218,68C214.7,68 211.4,68 208,68C209,64 209,64 211,61C211.66,61 212.32,61 213,61C213.37,60.19 213.37,60.19 213.75,59.36C215.28,56.47 217.09,53.9 219,51.25C219.7,50.27 220.4,49.28 221.13,48.27C221.74,47.52 222.36,46.77 223,46C223.66,46 224.32,46 225,46C225.33,44.68 225.66,43.36 226,42C226.66,42 227.32,42 228,42C227.53,41.24 227.05,40.47 226.56,39.69C225,37 225,37 224,34C223.34,34 222.68,34 222,34C220.27,32.14 220.27,32.14 218.38,29.69C217.74,28.89 217.11,28.09 216.46,27.26C215,25 215,25 215,22C213.68,22 212.36,22 211,22C208.75,19.75 208.75,19.75 207,17C207,15.68 207,14.36 207,13C206.24,12.75 205.47,12.51 204.69,12.25C201.68,10.85 200.57,9.9 199,7C198.69,4.38 198.69,4.38 199,2C199.66,1.34 200.32,0.68 201,0Z"
android:fillColor="#10744D"/>
<path
android:pathData="M161,19C163.31,19 163.31,19 166,20C167.29,21.42 168.58,22.85 169.73,24.38C171.15,26.27 171.15,26.27 173.75,28.69C176,31 176,31 177,34C177.99,34.33 178.98,34.66 180,35C181.47,42.1 181.47,42.1 179.19,46.5C178.1,47.74 178.1,47.74 177,49C176.34,49 175.68,49 175,49C174.77,49.7 174.55,50.4 174.31,51.13C172.66,54.74 170.71,57.09 168,60C167.34,60 166.68,60 166,60C165.73,60.76 165.46,61.53 165.19,62.31C164,65 163.3,66.23 161,68C158.52,68.29 158.52,68.29 155.81,68.19C154.91,68.16 154.01,68.13 153.08,68.11C152.39,68.07 151.71,68.04 151,68C152.73,63.96 155.46,60.71 158.19,57.31C159.18,56.07 160.17,54.82 161.16,53.57C161.88,52.66 161.88,52.66 162.62,51.74C164.49,49.38 166.34,47 168.19,44.63C168.74,43.92 169.29,43.21 169.86,42.48C170.23,41.99 170.61,41.5 171,41C169.45,37.53 167.38,34.77 165,31.81C164.3,30.93 163.6,30.05 162.88,29.14C161.18,26.93 161.18,26.93 159,26C158.88,23.63 158.88,23.63 159,21C159.66,20.34 160.32,19.68 161,19Z"
android:fillColor="#57BF7A"/>
<path
android:pathData="M176.56,18.94C177.77,18.97 177.77,18.97 179,19C179.27,19.64 179.54,20.28 179.81,20.94C180.89,23.33 180.89,23.33 184,24C185.94,26.18 185.94,26.18 188,28.88C190.63,32.39 190.63,32.39 193.75,35.45C195,37 195,37 195.6,39.66C194.69,44.71 191.71,47.61 188.38,51.38C187.13,52.82 185.89,54.26 184.65,55.71C184.03,56.42 183.42,57.12 182.79,57.84C180.5,60.6 178.5,63.52 176.53,66.5C174.45,68.53 172.97,68.48 170.13,68.5C168.75,68.37 167.37,68.22 166,68C166.61,64.04 168.6,61.45 170.94,58.25C171.65,57.27 172.36,56.28 173.09,55.27C174.04,54.14 174.04,54.14 175,53C175.66,53 176.32,53 177,53C177.33,51.68 177.66,50.36 178,49C178.66,49 179.32,49 180,49C180.27,48.44 180.54,47.89 180.81,47.31C182.1,44.8 183.54,42.41 185,40C183.56,38.23 182.13,36.46 180.69,34.69C179.89,33.7 179.09,32.72 178.26,31.7C176.17,29.09 176.17,29.09 174.22,27.34C173,26 173,26 172.75,22.88C173.09,19.02 173.09,19.02 176.56,18.94Z"
android:fillColor="#54C079"/>
<path
android:pathData="M188,19C190.09,18.55 190.09,18.55 193,19C195.53,21.14 197.54,23.68 199.63,26.25C200.2,26.93 200.77,27.61 201.36,28.32C202.93,30.2 204.48,32.08 206,34C206.56,34.69 207.12,35.37 207.69,36.08C209,38 209,38 208.9,40.42C207.85,43.44 206.42,45.7 204.56,48.31C203.95,49.2 203.33,50.08 202.69,50.99C202.13,51.65 201.58,52.32 201,53C200.34,53 199.68,53 199,53C199,53.99 199,54.98 199,56C197.36,57.69 195.69,59.35 194,61C193.26,62.27 192.53,63.54 191.81,64.81C190.6,66.62 190.6,66.62 189,68C185.59,68.6 182.42,68.42 179,68C180.21,64.56 181.39,62.5 184,60C184.33,59.01 184.66,58.02 185,57C186.64,55.3 188.31,53.64 190,52C191.65,50.17 193.28,48.32 194.88,46.44C195.68,45.51 196.48,44.58 197.3,43.62C199.27,41.19 199.27,41.19 198.76,38.66C198.51,38.11 198.26,37.56 198,37C197.34,37 196.68,37 196,37C192,32.53 192,32.53 192,30C191.01,29.67 190.02,29.34 189,29C187.19,26.75 187.19,26.75 186,24C186.81,21.19 186.81,21.19 188,19Z"
android:fillColor="#54BF78"/>
<path
android:pathData="M8,4C10.38,4.31 10.38,4.31 13,5C15,8 15,8 15,12C16.32,12 17.64,12 19,12C19.66,10.68 20.32,9.36 21,8C21.66,8 22.32,8 23,8C23,7.34 23,6.68 23,6C27.75,6.88 27.75,6.88 30,8C30,9.32 30,10.64 30,12C32.97,12 35.94,12 39,12C38.5,11.01 38.5,11.01 38,10C36.02,10 34.04,10 32,10C32,8.68 32,7.36 32,6C33.65,5.97 35.29,5.95 36.94,5.94C38.31,5.92 38.31,5.92 39.71,5.9C42,6 42,6 43,7C43.04,8.67 43.04,10.33 43,12C44.98,12 46.96,12 49,12C49,11.34 49,10.68 49,10C47.68,10 46.36,10 45,10C45,8.68 45,7.36 45,6C48.96,6 52.92,6 57,6C57,7.32 57,8.64 57,10C55.68,10 54.36,10 53,10C53,10.66 53,11.32 53,12C58.43,11.62 60.33,9.87 64,6C64.99,6 65.98,6 67,6C67,6.66 67,7.32 67,8C67.99,8.33 68.98,8.66 70,9C70.94,10.81 70.94,10.81 71,13C69.5,15.31 69.5,15.31 67,17C64.66,16.71 62.33,16.36 60,16C56.87,15.85 53.75,15.86 50.63,15.88C49.76,15.88 48.89,15.88 48,15.88C41.44,15.92 34.92,16.21 28.38,16.73C24.98,16.99 22.27,16.89 19,16C16.79,15.96 14.58,15.96 12.38,16C6.22,16.11 6.22,16.11 4,15C4,14.01 4,13.02 4,12C6.64,12 9.28,12 12,12C11.01,10.58 11.01,10.58 10,9.13C8,6 8,6 8,4ZM23,11C23.33,11.66 23.66,12.32 24,13C24.99,12.67 25.98,12.34 27,12C25.68,11.67 24.36,11.34 23,11ZM64,11C64,11.66 64,12.32 64,13C64.99,12.67 65.98,12.34 67,12C66.01,11.67 65.02,11.34 64,11Z"
android:fillColor="#19704E"/>
<path
android:pathData="M119.94,28.88C121.29,28.91 122.65,28.95 124,29C125.73,29 127.46,28.99 129.19,28.93C129.97,28.91 130.76,28.89 131.56,28.88C132.74,28.84 132.74,28.84 133.94,28.8C136,29 136,29 138,31C138.32,35.34 138.45,37.33 136,41C133.97,41.37 133.97,41.37 131.5,41.36C130.61,41.36 129.73,41.36 128.81,41.36C127.42,41.34 127.42,41.34 126,41.31C125.07,41.32 124.14,41.32 123.19,41.32C116.27,41.27 116.27,41.27 114,39C113.73,37.13 113.73,37.13 113.75,35C113.74,34.3 113.74,33.6 113.73,32.88C114.3,28.85 116.18,28.99 119.94,28.88Z"
android:fillColor="#10734D"/>
<path
android:pathData="M70,57C72.06,56.71 72.06,56.71 74.44,56.81C75.61,56.85 75.61,56.85 76.81,56.89C77.53,56.93 78.25,56.96 79,57C80.74,57 82.48,56.99 84.23,56.96C85.02,56.96 85.81,56.95 86.63,56.94C87.42,56.93 88.22,56.91 89.04,56.9C91,57 91,57 92,58C92.07,59.69 92.08,61.38 92.06,63.06C92.05,63.98 92.04,64.9 92.04,65.85C92.02,66.56 92.01,67.27 92,68C88.19,68.03 84.38,68.05 80.56,68.06C79.47,68.07 78.39,68.08 77.26,68.09C76.23,68.09 75.19,68.09 74.13,68.1C72.69,68.11 72.69,68.11 71.22,68.11C69,68 69,68 68,67C67.64,60.54 67.64,60.54 70,57Z"
android:fillColor="#0D744C"/>
<path
android:pathData="M192,35C195,37 195,37 195.6,39.6C194.7,44.69 191.74,47.57 188.38,51.38C187.13,52.82 185.89,54.26 184.65,55.71C183.73,56.77 183.73,56.77 182.79,57.84C180.5,60.6 178.5,63.52 176.53,66.5C174.45,68.53 172.97,68.48 170.13,68.5C168.75,68.37 167.37,68.22 166,68C166.61,64.04 168.6,61.45 170.94,58.25C172,56.77 172,56.77 173.09,55.27C173.72,54.52 174.35,53.77 175,53C175.66,53 176.32,53 177,53C177.33,51.68 177.66,50.36 178,49C178.66,49 179.32,49 180,49C180.25,48.48 180.49,47.97 180.75,47.44C182.4,44.23 184.2,41.12 186,38C186.66,39.77 186.66,39.77 187,42C186.03,43.82 186.03,43.82 184.5,45.69C183.94,46.38 183.39,47.07 182.82,47.79C182.22,48.52 181.62,49.25 181,50C179.81,51.54 178.62,53.08 177.44,54.63C174.69,58.14 171.88,61.59 169,65C169.99,65.33 170.98,65.66 172,66C178.59,59.6 184.02,52.71 189.27,45.16C189.84,44.45 190.41,43.73 191,43C191.66,43 192.32,43 193,43C192.67,40.36 192.34,37.72 192,35Z"
android:fillColor="#60BB7E"/>
<path
android:pathData="M117,6C117.99,6.33 118.98,6.66 120,7C120,8.65 120,10.3 120,12C123.3,12 126.6,12 130,12C130.33,10.02 130.66,8.04 131,6C131.99,6 132.98,6 134,6C134.29,12.05 134.29,12.05 134,14C130.58,16.28 129.32,16.22 125.31,16.13C123.82,16.1 123.82,16.1 122.3,16.07C121.54,16.05 120.78,16.02 120,16C119.9,16.62 119.79,17.24 119.69,17.88C119,20 119,20 116,22C113.81,21.63 113.81,21.63 112,21C112.33,20.01 112.66,19.02 113,18C113.99,17.67 114.98,17.34 116,17C116.33,13.37 116.66,9.74 117,6Z"
android:fillColor="#166E4C"/>
<path
android:pathData="M83.63,5.88C84.41,5.92 85.19,5.96 86,6C86.33,6.99 86.66,7.98 87,9C85.35,9.33 83.7,9.66 82,10C82,10.66 82,11.32 82,12C83.65,12 85.3,12 87,12C87.04,14 87.04,16 87,18C85.33,19.67 83.34,19.21 81.06,19.25C80.17,19.28 79.27,19.3 78.35,19.33C77.57,19.22 76.8,19.11 76,19C73.57,15.36 73.84,13.29 74,9C74.66,8.67 75.32,8.34 76,8C76.66,8.33 77.32,8.66 78,9C78,10.98 78,12.96 78,15C78.33,14.67 78.66,14.34 79,14C78.98,13.03 78.96,12.06 78.94,11.06C79.02,7.14 79.63,6.07 83.63,5.88Z"
android:fillColor="#19714F"/>
<path
android:pathData="M198,37C198.99,37.33 199.98,37.66 201,38C200.53,42.81 198.2,45.8 195.25,49.44C194.82,49.98 194.39,50.53 193.95,51.1C191.76,53.86 189.53,56.55 187.23,59.22C184.86,61.85 184.86,61.85 184,65C185.32,65.33 186.64,65.66 188,66C188,65.34 188,64.68 188,64C188.66,64 189.32,64 190,64C190.25,63.46 190.49,62.93 190.75,62.38C194.98,54.34 194.98,54.34 199,53C199,56 199,56 196.81,58.25C195.88,59.16 194.96,60.07 194,61C193.26,62.27 192.53,63.54 191.81,64.81C190.6,66.62 190.6,66.62 189,68C185.59,68.6 182.42,68.42 179,68C180.21,64.56 181.39,62.5 184,60C184.33,59.01 184.66,58.02 185,57C186.64,55.3 188.31,53.64 190,52C191.65,50.17 193.28,48.32 194.88,46.44C195.68,45.51 196.48,44.58 197.3,43.62C199.27,41.19 199.27,41.19 198.76,38.66C198.51,38.11 198.26,37.56 198,37Z"
android:fillColor="#5EBA7D"/>
<path
android:pathData="M141,4C144.02,4.33 145.6,4.61 147.81,6.75C149.23,9.44 149.47,11 149,14C145.55,16.3 144.05,16.34 140,16C139.34,15.34 138.68,14.68 138,14C138.3,9.86 138.68,7.48 141,4ZM143,9C143,10.32 143,11.64 143,13C143.66,12.67 144.32,12.34 145,12C144.67,11.01 144.34,10.02 144,9C143.67,9 143.34,9 143,9Z"
android:fillColor="#1A714E"/>
<path
android:pathData="M93,3C94.32,3 95.64,3 97,3C97.11,5.42 97.19,7.83 97.25,10.25C97.3,11.27 97.3,11.27 97.35,12.32C97.42,15.75 97.24,17.66 95.23,20.48C93,22 93,22 89,22C89.38,20.06 89.38,20.06 90,18C90.66,17.67 91.32,17.34 92,17C92.47,13.72 92.47,13.72 92.63,9.94C92.7,8.65 92.77,7.36 92.85,6.03C92.9,5.03 92.95,4.03 93,3Z"
android:fillColor="#18724F"/>
<path
android:pathData="M172,4C174.38,4.31 174.38,4.31 177,5C179.3,8.45 179.34,9.95 179,14C177,16 177,16 173.56,16.25C170,16 170,16 167,14C167,13.34 167,12.68 167,12C169.64,12 172.28,12 175,12C174.51,11.05 174.01,10.1 173.5,9.13C172,6 172,6 172,4Z"
android:fillColor="#1D7651"/>
<path
android:pathData="M107,4C111.58,4.48 111.58,4.48 113.38,6.69C114.21,9.76 113.81,11.94 113,15C110.48,16.26 109.15,15.92 106.38,15.56C105.56,15.46 104.74,15.36 103.9,15.25C103.27,15.17 102.65,15.09 102,15C102,14.01 102,13.02 102,12C104.64,12 107.28,12 110,12C109.5,11.05 109.01,10.1 108.5,9.13C107,6 107,6 107,4Z"
android:fillColor="#1B7250"/>
<path
android:pathData="M120.56,30.94C121.7,30.96 122.83,30.98 124,31C124.13,38.75 124.13,38.75 123,41C120.63,41.19 120.63,41.19 118,41C115.71,37.56 115.74,36.03 116,32C117,31 117,31 120.56,30.94Z"
android:fillColor="#09774D"/>
<path
android:pathData="M155,4C156.32,4 157.64,4 159,4C161.68,8.02 161.16,10.24 161,15C158.48,16.26 157.15,15.92 154.38,15.56C153.56,15.46 152.74,15.36 151.9,15.25C151.27,15.17 150.65,15.09 150,15C150,14.01 150,13.02 150,12C152.64,12 155.28,12 158,12C157.51,11.24 157.01,10.47 156.5,9.69C155,7 155,7 155,4Z"
android:fillColor="#187450"/>
<path
android:pathData="M23,49C23.33,49 23.66,49 24,49C24,50.65 24,52.3 24,54C20.18,56.47 16.15,56.44 11.75,56.63C11,56.66 10.26,56.7 9.49,56.74C7.66,56.84 5.83,56.92 4,57C3.67,58.32 3.34,59.64 3,61C4.32,61.99 5.64,62.98 7,64C4.63,64.19 4.63,64.19 2,64C0,61 0,61 0.19,58.44C1,56 1,56 4,54C6.71,53.72 9.35,53.54 12.06,53.44C17.19,53.43 17.19,53.43 22,52C22.33,51.01 22.66,50.02 23,49Z"
android:fillColor="#16734E"/>
<path
android:pathData="M163,1C163.99,1 164.98,1 166,1C166,6.28 166,11.56 166,17C164.68,16.67 163.36,16.34 162,16C161.97,13.69 161.95,11.38 161.94,9.06C161.93,7.77 161.91,6.49 161.9,5.16C162,2 162,2 163,1Z"
android:fillColor="#167650"/>
<path
android:pathData="M98,1C98.99,1 99.98,1 101,1C101,6.28 101,11.56 101,17C100.01,17 99.02,17 98,17C98,11.72 98,6.44 98,1Z"
android:fillColor="#15704D"/>
<path
android:pathData="M203,61C204.13,65.75 204.13,65.75 203,68C200.36,68 197.72,68 195,68C195.91,62.69 197.53,61 203,61Z"
android:fillColor="#0D744B"/>
<path
android:pathData="M32,6C35.3,6 38.6,6 42,6C42.33,6.99 42.66,7.98 43,9C42.01,10.49 42.01,10.49 41,12C40.34,12 39.68,12 39,12C38.67,11.34 38.34,10.68 38,10C36.02,10 34.04,10 32,10C32,8.68 32,7.36 32,6Z"
android:fillColor="#1E7152"/>
<path
android:pathData="M211,50C212.25,52.49 211.78,53.41 211,56C210.34,56 209.68,56 209,56C208.34,57.32 207.68,58.64 207,60C205.68,59.67 204.36,59.34 203,59C203.34,55.83 204,55 206.44,52.81C209,51 209,51 211,50Z"
android:fillColor="#0A774C"/>
<path
android:pathData="M202,2C203.94,2.81 203.94,2.81 206,4C206.33,4.99 206.66,5.98 207,7C207.66,7 208.32,7 209,7C208.67,8.32 208.34,9.64 208,11C205.68,10.6 204.14,10.09 202.19,8.75C201,7 201,7 201.31,4.31C201.54,3.55 201.77,2.79 202,2Z"
android:fillColor="#0A774D"/>
<path
android:pathData="M176.56,18.94C177.77,18.97 177.77,18.97 179,19C179,19.66 179,20.32 179,21C177.68,21 176.36,21 175,21C175.66,23.31 176.32,25.62 177,28C177.66,28 178.32,28 179,28C180.69,29.81 180.69,29.81 182,32C181.67,32.99 181.34,33.98 181,35C179.65,33.64 178.32,32.26 177,30.88C176.26,30.11 175.51,29.34 174.75,28.55C172.62,25.45 172.58,23.69 173,20C174,19 174,19 176.56,18.94Z"
android:fillColor="#5CB879"/>
<path
android:pathData="M70,57C72.16,56.71 72.16,56.71 74.63,56.81C75.44,56.84 76.26,56.87 77.1,56.89C78.04,56.95 78.04,56.95 79,57C79.33,57.66 79.66,58.32 80,59C76.7,59 73.4,59 70,59C70.48,63.65 70.48,63.65 72,68C70.68,67.67 69.36,67.34 68,67C67.75,60.38 67.75,60.38 70,57Z"
android:fillColor="#146A47"/>
<path
android:pathData="M188,19C189.32,19 190.64,19 192,19C192.33,19.99 192.66,20.98 193,22C192.01,22.66 191.02,23.32 190,24C190.66,25.65 191.32,27.3 192,29C191.01,29 190.02,29 189,29C187.19,26.81 187.19,26.81 186,24C186.81,21.19 186.81,21.19 188,19Z"
android:fillColor="#5DB87C"/>
<path
android:pathData="M127.06,16.94C128.52,16.97 128.52,16.97 130,17C130,18.32 130,19.64 130,21C129.34,21 128.68,21 128,21C128,21.66 128,22.32 128,23C126.68,23 125.36,23 124,23C123.62,21.34 123.29,19.68 123,18C124,17 124,17 127.06,16.94Z"
android:fillColor="#1F7354"/>
<path
android:pathData="M152,43C152.66,43 153.32,43 154,43C153.26,48.16 151.75,51.65 147.56,54.88C144.66,56.15 143.9,55.9 141,55C141.54,54.72 142.09,54.44 142.64,54.15C148.04,51.13 150.14,48.91 152,43Z"
android:fillColor="#157551"/>
<path
android:pathData="M49,53C49.66,53.33 50.32,53.66 51,54C52.37,54.07 53.75,54.08 55.13,54.06C57.04,54.03 57.04,54.03 59,54C59,54.66 59,55.32 59,56C57.42,56.03 55.83,56.05 54.25,56.06C52.93,56.08 52.93,56.08 51.58,56.1C49.21,56.01 47.29,55.57 45,55C42.99,55.27 40.99,55.59 39,56C41.21,51.59 44.68,51.75 49,53Z"
android:fillColor="#15744E"/>
<path
android:pathData="M205,30C205.66,30 206.32,30 207,30C207,30.66 207,31.32 207,32C207.66,32 208.32,32 209,32C213,36.47 213,36.47 213,39C213.99,39.33 214.98,39.66 216,40C215.01,41.49 215.01,41.49 214,43C212,42 212,42 211.19,39.75C209.74,36.39 207.6,34.53 205,32C205,31.34 205,30.68 205,30Z"
android:fillColor="#19734F"/>
<path
android:pathData="M33,55C33.66,55.33 34.32,55.66 35,56C33.63,58 33.63,58 32,60C31.34,60 30.68,60 30,60C29.67,60.99 29.34,61.98 29,63C25.44,64.19 25.44,64.19 22,65C22,64.34 22,63.68 22,63C22.89,62.61 23.77,62.22 24.69,61.81C28.12,59.93 30.37,57.87 33,55Z"
android:fillColor="#14744F"/>
<path
android:pathData="M131,6C131.99,6 132.98,6 134,6C134,8.64 134,11.28 134,14C132.35,14.33 130.7,14.66 129,15C129.35,14.4 129.7,13.8 130.06,13.19C131.33,10.89 131.33,10.89 130,8C130.33,7.34 130.66,6.68 131,6Z"
android:fillColor="#1C7451"/>
<path
android:pathData="M28.56,22.94C29.7,22.96 30.83,22.98 32,23C32.66,24.32 33.32,25.64 34,27C33.01,27.49 33.01,27.49 32,28C32,27.01 32,26.02 32,25C27.39,26.21 27.39,26.21 23,28C24.13,23.02 24.13,23.02 28.56,22.94Z"
android:fillColor="#16704D"/>
<path
android:pathData="M206,43C206,46.34 205.52,47.07 203.63,49.69C203.18,50.31 202.74,50.93 202.29,51.57C201.86,52.04 201.44,52.52 201,53C200.34,53 199.68,53 199,53C200.39,48.57 202.61,46.13 206,43Z"
android:fillColor="#5CB57B"/>
<path
android:pathData="M161,19C163.63,19.38 163.63,19.38 166,20C165.67,20.66 165.34,21.32 165,22C163.68,22 162.36,22 161,22C161,23.32 161,24.64 161,26C160.34,26 159.68,26 159,26C158.88,23.63 158.88,23.63 159,21C159.66,20.34 160.32,19.68 161,19Z"
android:fillColor="#5DB97B"/>
<path
android:pathData="M180,39C180.75,40.63 180.75,40.63 181,43C179.19,46.25 179.19,46.25 177,49C176.34,49 175.68,49 175,49C175.61,45.01 177.71,42.26 180,39Z"
android:fillColor="#5EBC7E"/>
<path
android:pathData="M176.56,18.94C177.77,18.97 177.77,18.97 179,19C179,19.66 179,20.32 179,21C177.68,21 176.36,21 175,21C175,22.65 175,24.3 175,26C174.34,26 173.68,26 173,26C172.96,24 172.96,22 173,20C174,19 174,19 176.56,18.94Z"
android:fillColor="#65BB7F"/>
<path
android:pathData="M150,12C152.48,12.49 152.48,12.49 155,13C155,13.99 155,14.98 155,16C153.35,15.67 151.7,15.34 150,15C150,14.01 150,13.02 150,12Z"
android:fillColor="#1E7855"/>
</vector>
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Some files were not shown because too many files have changed in this diff Show More