Dokończenie aplikacji

This commit is contained in:
Aleksandra Powaga 2021-02-16 00:01:12 +01:00
parent 8ad5aa6a60
commit 1441e3b3b8
17 changed files with 281 additions and 62 deletions

View File

@ -6,7 +6,8 @@ plugins {
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
buildToolsVersion
ndkVersion "22.0.7026061"
defaultConfig {
applicationId "com.example.haircosmeticsanalyser"
@ -17,7 +18,6 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
@ -31,10 +31,15 @@ android {
kotlinOptions {
jvmTarget = '1.8'
}
externalNativeBuild {
cmake {
path "src/main/c/CMakeLists.txt"
version "3.10.2"
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
@ -45,6 +50,7 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.0-beta01'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'com.rmtheis:tess-two:9.1.0'
implementation 'androidx.room:room-runtime:2.3.0-alpha04'
kapt "androidx.room:room-compiler:2.3.0-alpha04"
testImplementation 'junit:junit:4.+'

View File

@ -0,0 +1 @@
Aqua, Cetearyl Alcohol, Cetrimonium Chloride, Dimethicone, Behentrimonium Chloride, Isopropyl Myristate, Polyquaternium-10, Olea Europaea (Olive) Fruit Oil, Panthenol, Sodium Benzoate, Parfum, Citric Acid, CI 42090, CI 19140, CI 47005, CI 16035.

View File

@ -0,0 +1 @@
Aqua, Cetearyl Alcohol, Glyceryl Stearate SE, Propylene Glycol, Stearamidopropyl Dimethylamine, Panthenol, Niacinamide, Behentrimonium Chloride, Mel, Vanilla Planifolia Extract, Glutamic Acid, Dipropylene Glycol, Glycerin, Ethoxydiglycol, Butylene Glycol, Parfum, Benzyl Salicylate, Phenoxyethanol, Sodium Benzoate, Potassium Sorbate, Citric Acid.

View File

@ -0,0 +1 @@
Aqua, Cetearyl Alcohol, Cetrimonium Chloride, Lauryl Alcohol, Myristyl Alcohol, Hydrolyzed Wheat Protein, Simethicone, Citric Acid, Parfum, Propylene Glycol, Diazolidinyl Urea, Methylparaben, Propylparaben, Cl: 42090, Cl 19140.

View File

@ -0,0 +1 @@
Aqua, Cetearyl Alcohol, Butyrospermum Parkii (Shea Butter), Cucurbita Pepo (Pumpkin) Seed Oil, Behentrimonium Chloride, Brassica Oleracea Italica Seed Oil, Papaver Somniferum Seed Oil, Carthamus Tinctorius Seed Oil, Raphanus Sativus Seed Oil, Cetrimonium Chloride, Starch Hydroxypropyltrimonium Chloride, Phenoxyethanol, Benzoic Acid, Dehydroacetic Acid, Parfum, Citronellol, Geraniol, Linalool.

View File

@ -0,0 +1 @@
Aqua, Cetearyl Alcohol, Glycerin, Isopropyl Myristate, Stearamidopropyl Dimethylamine, Macadamia Ternifolia Seed Oil, Glycine Soja Oil, Sodium Hydroxide, Helianthus Annuus Seed Oil, Simmondsia Chinensis Oil, Prunus Amygdalus Dulcis Oil, Coco-Caprylate/Caprate, Cocos Nucifera Oil, Hydroxypropyl Guar Hydroxypropyltrimonium Chloride, Caprylyl Glycol, Citric Acid, Tartaric Acid, Cetyl Esters, Salicylic Acid, Caramel, Linalool, Geraniol, Coumarin, Limonene, Citral, Citronellol, Benzyl Alcohol, Benzyl Cinnamate, Benzyl Salicylate, Parfum.

View File

@ -0,0 +1,53 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
#opencv
set(OpenCV_STATIC on)
set(OpenCV_DIR $ENV{OpenCV_Android}/sdk/native/jni)
find_package(OpenCV REQUIRED)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.c )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
find_library(jnigraphics-lib jnigraphics)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${OpenCV-LIBS}
${jnigraphics-lib}
${log-lib} )

View File

@ -0,0 +1,15 @@
#include <jni.h>
#include <stdlib.h>
#include <time.h>
jint Jniint() {
srand((unsigned int) time(0));
int intrandom = (rand() % (990 - 101)) + 101;
return intrandom;
}
JNIEXPORT jint JNICALL
Java_com_example_haircosmeticsanalyser_FirstPage_Jniint(JNIEnv *env, jobject this) {
return (jint) Jniint();
}

View File

@ -1,20 +1,23 @@
package com.example.haircosmeticsanalyser
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.text.method.ScrollingMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat.requestPermissions
import androidx.core.content.ContextCompat.checkSelfPermission
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders
/**
@ -22,6 +25,12 @@ import androidx.fragment.app.Fragment
*/
class CameraFragment : Fragment() {
lateinit var viewModel: MainActivityViewModel
lateinit var searchIngredient: String
var fileName = "files/cosmetic1.txt"
var isDescriptionVisible = false
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -36,28 +45,70 @@ class CameraFragment : Fragment() {
(activity as AppCompatActivity).supportActionBar?.show()
(activity as AppCompatActivity?)!!.supportActionBar!!.title = getString(R.string.camera)
val context = context ?: false
val context = activity?.getApplicationContext()!!
viewModel = ViewModelProviders.of(this).get(MainActivityViewModel::class.java)
view.findViewById<Button>(R.id.btnPickImage).setOnClickListener {
/*if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(context as Context, android.Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
print("Lalala")
} else {
}
} else {
}*/
if (checkSelfPermission(requireContext(),
android.Manifest.permission.READ_EXTERNAL_STORAGE)
if (checkSelfPermission(
requireContext(),
android.Manifest.permission.READ_EXTERNAL_STORAGE
)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(requireActivity(),
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), PERMISSION_CODE)
requestPermissions(
requireActivity(),
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), PERMISSION_CODE
)
} else {
pickImageFromGallery()
}
}
view.findViewById<Button>(R.id.btnAnalyseImage).setOnClickListener {
var inci = view.context.assets.open(fileName).bufferedReader().use {
it.readText()
}
var list = inci.split(", ", ".")
list.toMutableList()
var finalMap : Map<String, String> = list.map { it to " " }.toMap()
var mutableFinalMap = finalMap.toMutableMap()
val txtViewAnalyseImageResponse = view.findViewById<TextView>(R.id.txtViewAnalyseImageResponse)
var inciAnalysis : String = ""
mutableFinalMap.forEach{ (key, value) ->
searchIngredient = key
var searchIngredientResponse = viewModel.getSearchResult(searchIngredient)
if (searchIngredientResponse != null) {
mutableFinalMap[key] = searchIngredientResponse.category
inciAnalysis += searchIngredientResponse.name + " - " + searchIngredientResponse.category + " \n" + searchIngredientResponse.description + "\n\n"
}
}
txtViewAnalyseImageResponse.text = inciAnalysis
view.findViewById<TextView>(R.id.txtViewAnalyseImageTitle).visibility = View.VISIBLE
view.findViewById<TextView>(R.id.txtViewAnalyseImageResponse).visibility = View.GONE
view.findViewById<TextView>(R.id.txtViewAnalyseImageSummaryTitle).visibility = View.VISIBLE
view.findViewById<TextView>(R.id.txtViewAnalyseImageSummary).visibility = View.VISIBLE
view.findViewById<TextView>(R.id.txtViewAnalyseImageSummary).text = summaryAlgorithm(context, mutableFinalMap)
}
view.findViewById<TextView>(R.id.txtViewAnalyseImageTitle).setOnClickListener {
val description = view.findViewById<TextView>(R.id.txtViewAnalyseImageResponse)
if (isDescriptionVisible) {
description.visibility = View.GONE
isDescriptionVisible = false
} else {
description.visibility = View.VISIBLE
isDescriptionVisible = true
}
}
view.findViewById<TextView>(R.id.txtViewAnalyseImageResponse).movementMethod =
ScrollingMovementMethod()
}
private fun pickImageFromGallery() {
@ -66,6 +117,47 @@ class CameraFragment : Fragment() {
startActivityForResult(intent, IMAGE_PICK_CODE)
}
private fun summaryAlgorithm(context: Context, map: MutableMap<String, String>) : String {
var list = map.values.toList()
var fragPosition = list.indexOf("zapach")
var poorCompositionText = ""
var firstActiveIngredient = ""
for (i in 0..(fragPosition/2)) {
if (list[i] != "inne") {
break
}
if (i == fragPosition/2-1) {
poorCompositionText = context.getString(R.string.poor_composition)
}
}
for (i in 0..fragPosition) {
if (list[i] != "inne") {
firstActiveIngredient = list[i]
break
}
}
var emolients = list.count{it == "emolient"}
var humectants = list.count{it == "humektant"}
var proteins = list.count{it == "proteina"}
return if (proteins > 0) {
poorCompositionText + context.getString(R.string.protein)
} else if (humectants > emolients) {
poorCompositionText + context.getString(R.string.humectant)
} else if (humectants == 0 && proteins == 0) {
poorCompositionText + context.getString(R.string.emollient)
} else if (firstActiveIngredient == "emolient") {
poorCompositionText + context.getString(R.string.emollient_humectant)
} else if (firstActiveIngredient == "humektant") {
poorCompositionText + context.getString(R.string.humectant_emollient)
} else {
""
}
}
companion object {
private val IMAGE_PICK_CODE = 1000
private val PERMISSION_CODE = 1001
@ -74,11 +166,13 @@ class CameraFragment : Fragment() {
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray) {
grantResults: IntArray
) {
when(requestCode) {
PERMISSION_CODE -> {
if (grantResults.size > 0 && grantResults[0] ==
PackageManager.PERMISSION_GRANTED) {
PackageManager.PERMISSION_GRANTED
) {
pickImageFromGallery()
} else {
Toast.makeText(context, "Permission denied", Toast.LENGTH_SHORT).show()

View File

@ -36,6 +36,8 @@ class DatabaseFragment : Fragment() {
view.findViewById<RecyclerView>(R.id.recyclerView).apply {
layoutManager = LinearLayoutManager(activity)
(layoutManager as LinearLayoutManager).setReverseLayout(true)
(layoutManager as LinearLayoutManager).setStackFromEnd(true)
recyclerViewAdapter = RecyclerViewAdapter(this@DatabaseFragment)
adapter = recyclerViewAdapter
val divider = DividerItemDecoration(context, LinearLayoutManager.VERTICAL)

View File

@ -1,22 +1,33 @@
package com.example.haircosmeticsanalyser
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.lang.System.*
/**
* A simple [Fragment] subclass as the default destination in the navigation.
*/
class FirstPage : Fragment() {
external fun Jniint() : Int
companion object {
init {
System.loadLibrary("native-lib")
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.first_page, container, false)
@ -38,5 +49,6 @@ class FirstPage : Fragment() {
}
(activity as AppCompatActivity).supportActionBar?.hide()
}
}

View File

@ -32,22 +32,4 @@ class MainActivityViewModel(app: Application) : AndroidViewModel(app) {
val ingredientDao = RoomAppDb.getAppDatabase((getApplication()))?.ingredientDAO()
return ingredientDao?.getSearchResult(search)
}
fun insertIngredientInfo(entity: IngredientEntity?) {
val ingredientDao = RoomAppDb.getAppDatabase(getApplication())?.ingredientDAO()
ingredientDao?.insertIngredient(entity)
getAllIngredients()
}
fun deleteIngredientInfo(entity: IngredientEntity?) {
val ingredientDao = RoomAppDb.getAppDatabase(getApplication())?.ingredientDAO()
ingredientDao?.deleteIngredient(entity)
getAllIngredients()
}
fun updateIngredientInfo(entity: IngredientEntity?) {
val ingredientDao = RoomAppDb.getAppDatabase(getApplication())?.ingredientDAO()
ingredientDao?.updateIngredient(entity)
getAllIngredients()
}
}

View File

@ -11,13 +11,4 @@ interface IngredientDao {
@Query(value = "SELECT * FROM ingredients WHERE name LIKE '%' || :search || '%'")
fun getSearchResult(search: String?) : IngredientEntity?
@Insert
fun insertIngredient(ingredient: IngredientEntity?)
@Delete
fun deleteIngredient(ingredient: IngredientEntity?)
@Update
fun updateIngredient(ingredient: IngredientEntity?)
}

View File

@ -22,7 +22,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:text="Wybierz zdjęcie"
android:textAllCaps="false"
@ -45,17 +44,61 @@
app:layout_constraintTop_toBottomOf="@+id/btnPickImage" />
<TextView
android:id="@+id/txtViewAnalyseImageTitle"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_height="40dp"
android:layout_margin="10dp"
android:background="@color/teal_200"
android:drawableEnd="@drawable/icon_arrow_drop_down"
android:visibility="invisible"
android:gravity="center_vertical"
android:paddingStart="15dp"
android:text="Analiza i opis składkników"
android:textColor="@color/white"
android:textSize="20sp"
app:layout_constraintTop_toBottomOf="@+id/imgViewImage" />
<TextView
android:id="@+id/txtViewAnalyseImageResponse"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="30dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="30dp"
android:text="@string/lorem"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
android:textSize="19sp"
android:scrollbars="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imgViewImage" />
app:layout_constraintTop_toBottomOf="@id/txtViewAnalyseImageTitle" />
<TextView
android:id="@+id/txtViewAnalyseImageSummaryTitle"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="10dp"
android:background="@color/teal_200"
android:gravity="center_vertical"
android:paddingStart="15dp"
android:text="Podsumowanie"
android:visibility="invisible"
android:textColor="@color/white"
android:textSize="20sp"
app:layout_constraintTop_toBottomOf="@+id/txtViewAnalyseImageResponse" />
<TextView
android:id="@+id/txtViewAnalyseImageSummary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="30dp"
android:text="Podsumowanie"
android:visibility="invisible"
android:textSize="19sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/txtViewAnalyseImageSummaryTitle" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -17,10 +17,10 @@
<TextView
android:id="@+id/txtViewName"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingStart="15dp"
android:padding="15dp"
android:text="Nazwa"
android:textColor="@color/white"
android:textSize="20sp"/>

View File

@ -4,7 +4,23 @@
<string name="camera">Analizuj zdjęcie</string>
<string name="search">Sprawdź składnik</string>
<string name="database"> Przeszukaj bazę danych</string>
<string name="database">Przeszukaj bazę danych</string>
<string name="poor_composition">Składniki aktywne w tym kosmetyku znajdują się daleko w składzie, więc nie będą miały dużego wpływu na włosy.\n\n</string>
<string name="emollient">Kosmetyk emolientowy\n
Utworzy warstwę okluzyjną, czyli nieprzepuszczającą niczego do wewnętrz, ani niewypuszczającą niczego na zewnątrz. Dzięki temu zatrzyma wilgoć w łuskach włosów, a przez to zmiękczy je i uelastyczni. Charakterystyczny film, który powstaje dzięki emolientom, dyscyplinuje puch powstały w zetknięciu z wilgocią. Dobrze dociąży oraz wygładzi włosy.\n
Nadmiar emolientów w pielęgnacji, może spowodować przetłuszczanie się włosów, ich nadmierne obciążenie i strączkowanie. </string>
<string name="humectant">Kosmetyk humektantowy\n
Nawilży włosy. Aby zamknąć nawilżenie we włosie należy domknąć pielęgnację kosmetykiem emolientowym, w przeciwnym wypadku włosy mogą się puszyć.</string>
<string name="protein">Kosmetyk proteinowy\n
Proteiny uzupełniają ubytki w strukturze włosa i/lub pokrywają go warstwą ochronną.\n
Jeśli w składzie kosmetyku nie ma silikonów, warto na koniec zastosować coś emolientowego, co domknie i wygładzi łuski włosów.</string>
<string name="emollient_humectant">Kosmetyk emolientowo-humektantowy\n
Przede wszystkim utworzy warstwę okluzyjną zatrzymującą wiglgoć we włosach, ale dzięki obecności humektantów również je nawilży.
</string>
<string name="humectant_emollient">Kosmetyk humektantowo-emolientowy\n
W produkcie znajduje się dużo emolientów domykających łuski włosów i wygładzających je, ale są one równoważone substancjami nawilżającymi znajdującymi się wysoko w składzie.
</string>
<string name="lorem">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</string>