commit c10d563e3fd2f981048654598556c857a8226b23 Author: Rokas Puzonas Date: Sun Nov 17 18:42:25 2024 +0200 finish lab1 diff --git a/Lab1/.gitignore b/Lab1/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/Lab1/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/Lab1/.idea/.gitignore b/Lab1/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/Lab1/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/Lab1/.idea/.name b/Lab1/.idea/.name new file mode 100644 index 0000000..84725a2 --- /dev/null +++ b/Lab1/.idea/.name @@ -0,0 +1 @@ +Lab_v4 \ No newline at end of file diff --git a/Lab1/.idea/compiler.xml b/Lab1/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/Lab1/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Lab1/.idea/deploymentTargetSelector.xml b/Lab1/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..fc8303f --- /dev/null +++ b/Lab1/.idea/deploymentTargetSelector.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Lab1/.idea/gradle.xml b/Lab1/.idea/gradle.xml new file mode 100644 index 0000000..7b3006b --- /dev/null +++ b/Lab1/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/Lab1/.idea/kotlinc.xml b/Lab1/.idea/kotlinc.xml new file mode 100644 index 0000000..148fdd2 --- /dev/null +++ b/Lab1/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Lab1/.idea/migrations.xml b/Lab1/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/Lab1/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/Lab1/.idea/misc.xml b/Lab1/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/Lab1/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/Lab1/.idea/runConfigurations.xml b/Lab1/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/Lab1/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/Lab1/app/.gitignore b/Lab1/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/Lab1/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Lab1/app/build.gradle.kts b/Lab1/app/build.gradle.kts new file mode 100644 index 0000000..55f171b --- /dev/null +++ b/Lab1/app/build.gradle.kts @@ -0,0 +1,81 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + id("kotlin-android") + id("kotlin-kapt") +} + +android { + namespace = "com.example.lab_v4" + compileSdk = 35 + + defaultConfig { + applicationId = "com.example.lab_v4" + minSdk = 24 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + viewBinding = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + implementation(libs.androidx.activity) + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.navigation.fragment.ktx) + implementation(libs.androidx.navigation.ui.ktx) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + + // Material Design + implementation("com.google.android.material:material:1.12.0") + + // Navigation Component + implementation("androidx.navigation:navigation-fragment-ktx:2.8.3") + implementation("androidx.navigation:navigation-ui-ktx:2.8.3") + + // Room components + implementation("androidx.room:room-runtime:2.6.1") + kapt("androidx.room:room-compiler:2.6.1") + implementation("androidx.room:room-ktx:2.6.1") + + // Lifecycle components + implementation("androidx.lifecycle:lifecycle-extensions:2.2.0") + implementation("androidx.lifecycle:lifecycle-common-java8:2.8.7") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7") + + // Kotlin components + //implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72") + //api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9") + //api("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9") + // implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0") + + //DataBinding + //kapt("com.android.databinding:compiler:3.2.0-alpha10") +} \ No newline at end of file diff --git a/Lab1/app/proguard-rules.pro b/Lab1/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/Lab1/app/proguard-rules.pro @@ -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 \ No newline at end of file diff --git a/Lab1/app/src/androidTest/java/com/example/lab_v4/ExampleInstrumentedTest.kt b/Lab1/app/src/androidTest/java/com/example/lab_v4/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..4c5a2c8 --- /dev/null +++ b/Lab1/app/src/androidTest/java/com/example/lab_v4/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.lab_v4 + +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.lab_v4", appContext.packageName) + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/AndroidManifest.xml b/Lab1/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..15e1965 --- /dev/null +++ b/Lab1/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Lab1/app/src/main/assets/database/LDB.sqlite3 b/Lab1/app/src/main/assets/database/LDB.sqlite3 new file mode 100644 index 0000000..aa02c64 Binary files /dev/null and b/Lab1/app/src/main/assets/database/LDB.sqlite3 differ diff --git a/Lab1/app/src/main/java/com/example/lab_v4/GlobalViewModel.kt b/Lab1/app/src/main/java/com/example/lab_v4/GlobalViewModel.kt new file mode 100644 index 0000000..ad2d541 --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/GlobalViewModel.kt @@ -0,0 +1,44 @@ +package com.example.lab_v4 + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.LiveData +import androidx.lifecycle.switchMap +import androidx.lifecycle.viewModelScope +import com.example.lab_v4.db.Matavimas +import com.example.lab_v4.db.MatavimasDao +import com.example.lab_v4.db.MyDatabase +import com.example.lab_v4.db.Stiprumas +import com.example.lab_v4.db.StiprumasDao +import com.example.lab_v4.db.Vartotojas +import com.example.lab_v4.db.VartotojasDao +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +class GlobalViewModel(application: Application): AndroidViewModel(application) { + + val vartotojai: LiveData> + val stiprumai: LiveData> + val matavimai: LiveData> + + private val vartotojaiDao: VartotojasDao + private val matavimaiDao: MatavimasDao + private val stiprumaiDao: StiprumasDao + + init { + var db = MyDatabase.getDatabase(application) + vartotojaiDao = db.vartotojasDao() + matavimaiDao = db.matavimasDao() + stiprumaiDao = db.stiprumasDao() + + vartotojai = vartotojaiDao.list() + matavimai = matavimaiDao.list() + stiprumai = stiprumaiDao.list() + } + + fun addVartotojas(vartotojas: Vartotojas) { + viewModelScope.launch(Dispatchers.IO) { + vartotojaiDao.insert(vartotojas) + } + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/MainActivity.kt b/Lab1/app/src/main/java/com/example/lab_v4/MainActivity.kt new file mode 100644 index 0000000..d8a678a --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/MainActivity.kt @@ -0,0 +1,83 @@ +package com.example.lab_v4 + +import android.os.Bundle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.replace +import androidx.navigation.findNavController +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.NavigationUI.setupWithNavController +import androidx.navigation.ui.setupActionBarWithNavController +import androidx.navigation.ui.setupWithNavController +import com.example.lab_v4.databinding.ActivityMainBinding +import com.example.lab_v4.fragments.ListFragment +import com.example.lab_v4.fragments.MapFragment +import com.google.android.material.bottomnavigation.BottomNavigationView + +class MainActivity : AppCompatActivity() { + lateinit var binding: ActivityMainBinding; + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + //setupActionBarWithNavController(findNavController(R.id.fragmentContainerView)) +// ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> +// val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) +// v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) +// insets +// } + +// val navController = findNavController(R.id.fragmentContainerView) +// val appBarConfiguration = AppBarConfiguration(setOf(R.id.mapFragment, R.id.listFragment)) +// setupActionBarWithNavController(navController, appBarConfiguration) + +// var bottomNavigationView = binding.bottomNavigationView; +// var navController = this.findNavController(R.id.fragmentContainerView); +// setupWithNavController(bottomNavigationView, navController); + +// replaceFragment(MapFragment()) + + } + + private fun replaceFragment(fragment: Fragment) { +// var fragmentManager = supportFragmentManager +// var fragmentTransaction = fragmentManager.beginTransaction() +// fragmentTransaction.replace(R.id.frame_layout, fragment) +// fragmentTransaction.commit() + } + + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + + val navView: BottomNavigationView = binding.bottomNavigationView + val navController = findNavController(R.id.fragmentContainerView) + //setupActionBarWithNavController(findNavController(R.id.fragmentContainerView)) + navView.setupWithNavController(navController) + binding.bottomNavigationView.setOnItemSelectedListener { item -> + when (item.itemId) { + R.id.navigation_map -> navController.navigate(R.id.mapFragment) + R.id.navigation_list -> navController.navigate(R.id.listFragment) + } + true; + } + +// val navView: BottomNavigationView = binding.bottomNavigationView +// val navController = findNavController(R.id.fragmentContainerView) +// // Passing each menu ID as a set of Ids because each +// // menu should be considered as top level destinations. +// val appBarConfiguration = AppBarConfiguration(setOf(R.id.navigation_map, R.id.navigation_list)) +// setupActionBarWithNavController(navController, appBarConfiguration) +// navView.setupWithNavController(navController) + } + + override fun onSupportNavigateUp(): Boolean { + val navController = findNavController(R.id.fragmentContainerView) + return navController.navigateUp() || super.onSupportNavigateUp() + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/MeasurementPoint.kt b/Lab1/app/src/main/java/com/example/lab_v4/MeasurementPoint.kt new file mode 100644 index 0000000..6702edb --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/MeasurementPoint.kt @@ -0,0 +1,7 @@ +package com.example.lab_v4 + +data class MeasurementPoint( + val x: Int, + val y: Int, + val strengths: Triple +); diff --git a/Lab1/app/src/main/java/com/example/lab_v4/Vec2Int.kt b/Lab1/app/src/main/java/com/example/lab_v4/Vec2Int.kt new file mode 100644 index 0000000..f9170a6 --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/Vec2Int.kt @@ -0,0 +1,6 @@ +package com.example.lab_v4 + +data class Vec2Int( + val x: Int, + val y: Int +) \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/db/Matavimas.kt b/Lab1/app/src/main/java/com/example/lab_v4/db/Matavimas.kt new file mode 100644 index 0000000..60bf619 --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/db/Matavimas.kt @@ -0,0 +1,13 @@ +package com.example.lab_v4.db + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "matavimai") +data class Matavimas( + @PrimaryKey(autoGenerate = true) + val matavimas: Int, + val x: Int, + val y: Int, + val atstumas: Float +) diff --git a/Lab1/app/src/main/java/com/example/lab_v4/db/MatavimasDao.kt b/Lab1/app/src/main/java/com/example/lab_v4/db/MatavimasDao.kt new file mode 100644 index 0000000..29c9e5c --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/db/MatavimasDao.kt @@ -0,0 +1,12 @@ +package com.example.lab_v4.db + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Query + +@Dao +interface MatavimasDao { + + @Query("SELECT * FROM matavimai") + fun list(): LiveData> +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/db/MyDatabase.kt b/Lab1/app/src/main/java/com/example/lab_v4/db/MyDatabase.kt new file mode 100644 index 0000000..2abaf56 --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/db/MyDatabase.kt @@ -0,0 +1,38 @@ +package com.example.lab_v4.db + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database( + entities = [Vartotojas::class, Matavimas::class, Stiprumas::class], + version = 2, + exportSchema = false +) +abstract class MyDatabase : RoomDatabase() { + abstract fun vartotojasDao(): VartotojasDao + abstract fun matavimasDao(): MatavimasDao + abstract fun stiprumasDao(): StiprumasDao + + companion object { + @Volatile + private var INSTANCE: MyDatabase? = null + + fun getDatabase(context: Context): MyDatabase { + if (INSTANCE != null) { + return INSTANCE!!; + } + + synchronized(this){ + val instance = Room.databaseBuilder( + context.applicationContext, + MyDatabase::class.java, + "LDB" + ).createFromAsset("database/LDB.sqlite3").build() + INSTANCE = instance + return instance + } + } + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/db/Stiprumas.kt b/Lab1/app/src/main/java/com/example/lab_v4/db/Stiprumas.kt new file mode 100644 index 0000000..72e8c7c --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/db/Stiprumas.kt @@ -0,0 +1,13 @@ +package com.example.lab_v4.db + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "stiprumai") +data class Stiprumas( + @PrimaryKey(autoGenerate = true) + val id: Int, + val sensorius: String, + val stiprumas: Int, + val matavimas: Int +) diff --git a/Lab1/app/src/main/java/com/example/lab_v4/db/StiprumasDao.kt b/Lab1/app/src/main/java/com/example/lab_v4/db/StiprumasDao.kt new file mode 100644 index 0000000..df37cee --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/db/StiprumasDao.kt @@ -0,0 +1,12 @@ +package com.example.lab_v4.db + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Query + +@Dao +interface StiprumasDao { + + @Query("SELECT * FROM stiprumai") + fun list(): LiveData> +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/db/Vartotojas.kt b/Lab1/app/src/main/java/com/example/lab_v4/db/Vartotojas.kt new file mode 100644 index 0000000..b1cf8e4 --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/db/Vartotojas.kt @@ -0,0 +1,13 @@ +package com.example.lab_v4.db + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "vartotojai") +data class Vartotojas( + @PrimaryKey(autoGenerate = true) + val id: Int, + val mac: String, + val sensorius: String, + val stiprumas: Int +) diff --git a/Lab1/app/src/main/java/com/example/lab_v4/db/VartotojasDao.kt b/Lab1/app/src/main/java/com/example/lab_v4/db/VartotojasDao.kt new file mode 100644 index 0000000..ac98cae --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/db/VartotojasDao.kt @@ -0,0 +1,20 @@ +package com.example.lab_v4.db + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query + +@Dao +interface VartotojasDao { + + @Insert + fun insert(vartotojas: Vartotojas) + + @Delete + fun delete(vartotojas: Vartotojas) + + @Query("SELECT * FROM vartotojai") + fun list(): LiveData> +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/fragments/AddFragment.kt b/Lab1/app/src/main/java/com/example/lab_v4/fragments/AddFragment.kt new file mode 100644 index 0000000..62a65df --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/fragments/AddFragment.kt @@ -0,0 +1,51 @@ +package com.example.lab_v4.fragments + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import com.example.lab_v4.GlobalViewModel +import com.example.lab_v4.R +import com.example.lab_v4.databinding.FragmentAddBinding +import com.example.lab_v4.databinding.FragmentListBinding +import com.example.lab_v4.db.Vartotojas + +class AddFragment : Fragment() { + private lateinit var globalViewModel: GlobalViewModel + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val binding = FragmentAddBinding.inflate(inflater, container, false) + globalViewModel = ViewModelProvider(requireActivity()).get(GlobalViewModel::class.java) + + binding.button.setOnClickListener { + if (binding.editMac.text.isEmpty() || binding.editSensorius1.text.isEmpty() || binding.editSensorius2.text.isEmpty() || binding.editSensorius3.text.isEmpty()) { + Toast.makeText(requireContext(), "ERROR: All fields are required", Toast.LENGTH_LONG).show() + return@setOnClickListener + } + + try { + var mac = binding.editMac.text.toString() + var sensorius1 = Integer.parseInt(binding.editSensorius1.text.toString()) + var sensorius2 = Integer.parseInt(binding.editSensorius2.text.toString()) + var sensorius3 = Integer.parseInt(binding.editSensorius3.text.toString()) + globalViewModel.addVartotojas(Vartotojas(0, mac, "wiliboxas1", sensorius1)) + globalViewModel.addVartotojas(Vartotojas(0, mac, "wiliboxas2", sensorius2)) + globalViewModel.addVartotojas(Vartotojas(0, mac, "wiliboxas3", sensorius3)) + + Toast.makeText(requireContext(), "Added", Toast.LENGTH_LONG).show() + findNavController().navigate(R.id.action_addFragment_to_listFragment) + } catch (_: NumberFormatException) { + Toast.makeText(requireContext(), "ERROR: Failed to parse numbers", Toast.LENGTH_LONG).show() + } + } + + return binding.root; + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/fragments/ListAdapter.kt b/Lab1/app/src/main/java/com/example/lab_v4/fragments/ListAdapter.kt new file mode 100644 index 0000000..ec07779 --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/fragments/ListAdapter.kt @@ -0,0 +1,54 @@ +package com.example.lab_v4.fragments + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.example.lab_v4.R +import com.example.lab_v4.db.Vartotojas + +class ListAdapter : RecyclerView.Adapter() +{ + private var vartotojai = emptyList>(); + + class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { + val rowNumber: TextView + val mac: TextView + val sensor1: TextView + val sensor2: TextView + val sensor3: TextView + + init { + rowNumber = view.findViewById(R.id.rowNumber) + mac = view.findViewById(R.id.mac) + sensor1 = view.findViewById(R.id.sensor1) + sensor2 = view.findViewById(R.id.sensor2) + sensor3 = view.findViewById(R.id.sensor3) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { + return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.custom_row, parent, false)) + } + + override fun getItemCount(): Int { + return vartotojai.size + } + + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + var currentItem = vartotojai[position] + assert(currentItem.size == 3) + + holder.rowNumber.setText((position+1).toString()) + holder.mac.text = currentItem[0].mac + holder.sensor1.text = currentItem[0].stiprumas.toString() + holder.sensor2.text = currentItem[1].stiprumas.toString() + holder.sensor3.text = currentItem[2].stiprumas.toString() + } + + fun setData(data: List>) { + this.vartotojai = data + notifyDataSetChanged() + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/fragments/ListFragment.kt b/Lab1/app/src/main/java/com/example/lab_v4/fragments/ListFragment.kt new file mode 100644 index 0000000..308d395 --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/fragments/ListFragment.kt @@ -0,0 +1,43 @@ +package com.example.lab_v4.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import com.example.lab_v4.GlobalViewModel +import com.example.lab_v4.R +import com.example.lab_v4.databinding.FragmentListBinding + + +class ListFragment : Fragment() { + private lateinit var globalViewModel: GlobalViewModel + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val binding = FragmentListBinding.inflate(inflater, container, false) + + val adapter = ListAdapter() + val recyclerView = binding.recycler + recyclerView.adapter = adapter + recyclerView.layoutManager = LinearLayoutManager(requireContext()) + + globalViewModel = ViewModelProvider(requireActivity()).get(GlobalViewModel::class.java) + globalViewModel.vartotojai.observe(viewLifecycleOwner, { vartotojai -> + var groupedVartotojai = vartotojai.sortedBy { v -> v.sensorius }.groupBy { v -> v.mac } + adapter.setData(groupedVartotojai.values.toList()) + }) + + binding.floatingActionButton.setOnClickListener { + findNavController().navigate(R.id.action_listFragment_to_addFragment) + } + + return binding.root + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/fragments/MapFragment.kt b/Lab1/app/src/main/java/com/example/lab_v4/fragments/MapFragment.kt new file mode 100644 index 0000000..8b43274 --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/fragments/MapFragment.kt @@ -0,0 +1,132 @@ +package com.example.lab_v4.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.ViewModelProvider +import com.example.lab_v4.GlobalViewModel +import com.example.lab_v4.MeasurementPoint +import com.example.lab_v4.Vec2Int +import com.example.lab_v4.databinding.FragmentMapBinding +import kotlin.math.pow + + +class MapFragment : Fragment() { + + lateinit var binding: FragmentMapBinding + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentMapBinding.inflate(inflater, container, false) + + val globalViewModel = ViewModelProvider(requireActivity()).get(GlobalViewModel::class.java) + globalViewModel.stiprumai.observe(viewLifecycleOwner) { + updateMapDatapoints() + updateMapHighlights() + binding.myMapView.invalidate() + } + + globalViewModel.matavimai.observe(viewLifecycleOwner) { + updateMapDatapoints() + updateMapHighlights() + binding.myMapView.invalidate() + } + + globalViewModel.vartotojai.observe(viewLifecycleOwner, { vartotojai -> + updateMapHighlights() + binding.myMapView.invalidate() + }) + return binding.root + } + + private fun updateMapDatapoints() + { + val globalViewModel = ViewModelProvider(requireActivity()).get(GlobalViewModel::class.java) + var matavimai = globalViewModel.matavimai.value + + var datapoints = mutableListOf(); + if (matavimai != null) { + for (matavimas in matavimai) { + datapoints.add(Vec2Int(matavimas.x, matavimas.y)) + } + } + + binding.myMapView.datapoints = datapoints; + } + + private fun updateMapHighlights() + { + val globalViewModel = ViewModelProvider(requireActivity()).get(GlobalViewModel::class.java) + + var datapoints = mutableListOf(); + + var matavimai = globalViewModel.matavimai.value + var stiprumai = globalViewModel.stiprumai.value + if (matavimai != null && stiprumai != null) { + for (matavimas in matavimai) { + var distances = mutableListOf>() + for (stiprumas in stiprumai.filter { stiprumas -> stiprumas.matavimas == matavimas.matavimas }) { + distances.add(Pair(stiprumas.stiprumas.toFloat(), stiprumas.sensorius)); + } + if (distances.size != 3) continue + + var distance1 = distances.find { p -> p.second == "wiliboxas1" } + if (distance1 == null) continue + var distance2 = distances.find { p -> p.second == "wiliboxas2" } + if (distance2 == null) continue + var distance3 = distances.find { p -> p.second == "wiliboxas3" } + if (distance3 == null) continue + + datapoints.add(MeasurementPoint(matavimas.x, matavimas.y, Triple(distance1.first, distance2.first, distance3.first))) + } + } + + var highlights = mutableListOf() + + var vartotojai = globalViewModel.vartotojai.value + if (vartotojai != null) { + var groupedVartotojai = vartotojai.sortedBy { v -> v.sensorius }.groupBy { v -> v.mac } + for (group in groupedVartotojai.values) { + + var strength1 = group.find { p -> p.sensorius == "wiliboxas1" } + if (strength1 == null) continue + var strength2 = group.find { p -> p.sensorius == "wiliboxas2" } + if (strength2 == null) continue + var strength3 = group.find { p -> p.sensorius == "wiliboxas3" } + if (strength3 == null) continue + + var nearestPoint = findNearest(datapoints, Triple(strength1.stiprumas.toFloat(), strength2.stiprumas.toFloat(), strength3.stiprumas.toFloat())) + highlights.add(nearestPoint) + } + } + + binding.myMapView.highlights = highlights + } + + private fun findNearest(datapoints: List, strengths: Triple): Vec2Int? + { + var nearest: MeasurementPoint? = null; + var nearestDistance = 0f + + for (datapoint in datapoints) { + var distance = (datapoint.strengths.first - strengths.first).pow(2) + + (datapoint.strengths.second - strengths.second).pow(2) + + (datapoint.strengths.third - strengths.third).pow(2) + + if (nearest == null || (nearestDistance > distance)) { + nearest = datapoint + nearestDistance = distance + } + } + + if (nearest != null) { + return Vec2Int(nearest.x, nearest.y) + } else { + return null; + } + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/java/com/example/lab_v4/fragments/MyMapView.kt b/Lab1/app/src/main/java/com/example/lab_v4/fragments/MyMapView.kt new file mode 100644 index 0000000..168043f --- /dev/null +++ b/Lab1/app/src/main/java/com/example/lab_v4/fragments/MyMapView.kt @@ -0,0 +1,108 @@ +package com.example.lab_v4 + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.util.AttributeSet +import android.view.View + +class MyMapView(context: Context?, attrs: AttributeSet?) : View(context, attrs) { + + var datapoints: List? = null + var highlights: List = listOf(); + + var bgPaint = Paint() + init { + bgPaint.color = Color.GRAY; + bgPaint.strokeWidth = 2f; + } + + var datapointPaint = Paint() + init { + datapointPaint.color = Color.RED; + datapointPaint.strokeWidth = 2f; + } + + var highlightPaint = Paint() + init { + highlightPaint.color = Color.CYAN; + highlightPaint.strokeWidth = 2f; + } + + var textPaint = Paint() + init { + textPaint.color = Color.BLACK; + textPaint.strokeWidth = 3f; + textPaint.textSize = 25f; + textPaint.textAlign = Paint.Align.CENTER; + } + + private fun getDimensions(): Pair, Pair>? { + if (datapoints == null) return null + if (datapoints!!.size <= 1) return null; + + var minX = datapoints!![0].x + var maxX = datapoints!![0].x + var minY = datapoints!![0].y + var maxY = datapoints!![0].y + + for (matavimas in datapoints!!) { + minX = Math.min(minX, matavimas.x) + maxX = Math.max(maxX, matavimas.x) + minY = Math.min(minY, matavimas.y) + maxY = Math.max(maxY, matavimas.y) + } + + return Pair(Pair(minX, maxX), Pair(minY, maxY)) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + if (datapoints == null) return + + var dimentions = getDimensions() + if (dimentions == null) return; + + var minX = dimentions.first.first; + var maxX = dimentions.first.second; + var minY = dimentions.second.first; + var maxY = dimentions.second.second; + + var myWidth = (maxX - minX) + 1; + var myHeight = (maxY - minY) + 1; + + var margin = 20f; + var gapX = (width - margin * 2) / myWidth; + var gapY = (height - margin * 2) / myHeight; + + for (oy in 0.. point != null && point.x == x && point.y == y }; + if (highlightIndex != -1) { + paint = highlightPaint; + } else if (datapoints!!.find { point -> point.x == x && point.y == y } != null) { + paint = datapointPaint; + } + var circleX = gapX * (ox + 0.5f) + margin; + var circleY = gapY * (myHeight - oy + 0.5f - 1) + margin; + canvas.drawCircle(circleX, circleY, 12.5f, paint); + + if (highlightIndex != -1) { + canvas.drawText("${highlightIndex+1}", circleX, circleY + 8, textPaint); + } + } + } + + canvas.drawLine(0f, 0f, width.toFloat(), 0f, bgPaint); + canvas.drawLine(0f, height.toFloat(), width.toFloat(), height.toFloat(), bgPaint); + + canvas.drawLine(0f, 0f, 0f, height.toFloat(), bgPaint); + canvas.drawLine(width.toFloat(), 0f, width.toFloat(), height.toFloat(), bgPaint); + + } +} \ No newline at end of file diff --git a/Lab1/app/src/main/res/drawable/ic_launcher_background.xml b/Lab1/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/Lab1/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Lab1/app/src/main/res/drawable/ic_launcher_foreground.xml b/Lab1/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/Lab1/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Lab1/app/src/main/res/layout/activity_main.xml b/Lab1/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..0aa18c8 --- /dev/null +++ b/Lab1/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/Lab1/app/src/main/res/layout/custom_row.xml b/Lab1/app/src/main/res/layout/custom_row.xml new file mode 100644 index 0000000..2de9cda --- /dev/null +++ b/Lab1/app/src/main/res/layout/custom_row.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Lab1/app/src/main/res/layout/fragment_add.xml b/Lab1/app/src/main/res/layout/fragment_add.xml new file mode 100644 index 0000000..8def09a --- /dev/null +++ b/Lab1/app/src/main/res/layout/fragment_add.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + +