Skip to content

Commit

Permalink
#341# Arranging Package Design # Creating new database in MVVM archit…
Browse files Browse the repository at this point in the history
…ecture # Using Dependency Injection # Using not hard-coded variable names # Using Coroutine # Using ViewModel #Add new dependencies on gradle files#
  • Loading branch information
egecan.serbester committed Oct 22, 2023
1 parent 6008b3a commit 5bfc4cf
Show file tree
Hide file tree
Showing 27 changed files with 415 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-android'
id 'kotlin-kapt'
id 'org.jetbrains.dokka'
id 'dagger.hilt.android.plugin'
id 'com.google.dagger.hilt.android'
}
//
android {
Expand Down Expand Up @@ -29,11 +34,11 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '17'
}
}

Expand Down Expand Up @@ -61,13 +66,55 @@ dependencies {
implementation("androidx.recyclerview:recyclerview-selection:1.1.0")


// ViewModel
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
// ViewModel utilities for Compose
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
// LiveData
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")
// Lifecycles only (without ViewModel or LiveData)
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
//lifecycle for ViewModel and LiveData
def lifecycle_version = "2.6.1"
def coroutine_lifecycle_version = "2.6.2"

implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version") // ViewModel
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version")
implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version")

//lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "androidx.lifecycle:lifecycle-common-java8:2.6.2"

//noinspection LifecycleAnnotationProcessorWithJava8
kapt("androidx.lifecycle:lifecycle-compiler:$lifecycle_version")

// Room
def room_version = "2.6.0"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$room_version")

//androidx
implementation("androidx.concurrent:concurrent-futures-ktx:1.1.0")

// Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"

def coroutine_version = "1.6.4"
// Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"

// Coroutine Lifecycle Scopes
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$coroutine_lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$coroutine_lifecycle_version"

//apache for string utils
implementation 'org.apache.commons:commons-text:1.9'

//dagger-hilt
implementation("com.google.dagger:hilt-android:2.46")
//because it gives an error with hilt-android 2.46 it's older version. I wastes my 2 hours..
kapt("com.google.dagger:hilt-android-compiler:2.44")
//to add dagger-hilt by viewModel()
implementation "androidx.fragment:fragment-ktx:1.6.1"

//Gson
implementation 'com.google.code.gson:gson:2.10.1'

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".DarpApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.disasterresponseplatform

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

/** This is for Hilt
* It basically for hold the ActivationContext on Hilt, thanks to this class whenever Hilt needs an ActivationContext
* it comes from there
* Warning: You need to add Manifest because it's an activity otherwise you will get an error
*/
@HiltAndroidApp
class DarpApplication: Application() {
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,27 @@ import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.example.disasterresponseplatform.data.database.need.Need
import com.example.disasterresponseplatform.data.enums.Urgency
import com.example.disasterresponseplatform.databinding.ActivityMainBinding
import com.example.disasterresponseplatform.ui.HomePageFragment
import com.example.disasterresponseplatform.ui.activity.ActivityFragment
import com.example.disasterresponseplatform.ui.activity.need.NeedViewModel
import com.example.disasterresponseplatform.ui.authentication.LoginFragment
import com.example.disasterresponseplatform.ui.authentication.RegistrationFragment
import com.example.disasterresponseplatform.ui.map.MapFragment
import com.example.disasterresponseplatform.ui.network.NetworkFragment
import com.example.disasterresponseplatform.ui.profile.ProfileFragment
import com.example.disasterresponseplatform.utils.DateUtil
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding
Expand All @@ -30,6 +37,8 @@ class MainActivity : AppCompatActivity() {
private val loginFragment = LoginFragment()
private val registrationFragment = RegistrationFragment()

private lateinit var needViewModel: NeedViewModel


private lateinit var toggle: ActionBarDrawerToggle
override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -43,6 +52,18 @@ class MainActivity : AppCompatActivity() {
replaceFragment(homePageFragment)
navBarListener()
toggleListener()

// it is created by dependency Injection without creating any of db, dao or repo
val getNeedViewModel: NeedViewModel by viewModels()
needViewModel = getNeedViewModel

}

private fun tryNeedViewModel(){
val need = Need(null,"Egecan","Clothes","T-Shirt",DateUtil.getDate("dd-MM-yy").toString(),50,"İstanbul",Urgency.CRITICAL.type)
needViewModel.insertNeed(need)
val location = needViewModel.getLocation("Egecan")
Toast.makeText(this,location,Toast.LENGTH_SHORT).show()
}

private fun toggleListener(){
Expand All @@ -58,6 +79,7 @@ class MainActivity : AppCompatActivity() {
R.id.miRegister -> replaceNavFragment(registrationFragment)
R.id.miNetwork -> replaceNavFragment(networkFragment)
R.id.miLogout -> Toast.makeText(this,"Logout",Toast.LENGTH_SHORT).show()
R.id.miAddNeed -> tryNeedViewModel()
}
binding.root.closeDrawer(GravityCompat.START) //whenever clicked item on drawer, closing it automatically
true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.example.disasterresponseplatform.adapter

import android.content.Intent
import android.os.Looper
import android.view.LayoutInflater
import android.view.ViewGroup
Expand All @@ -9,12 +8,10 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.recyclerview.widget.RecyclerView
import com.example.disasterresponseplatform.R
import com.example.disasterresponseplatform.data.ActivityEnum
import com.example.disasterresponseplatform.data.DummyActivity
import com.example.disasterresponseplatform.data.PredefinedTypes
import com.example.disasterresponseplatform.data.enums.ActivityEnum
import com.example.disasterresponseplatform.data.models.DummyActivity
import com.example.disasterresponseplatform.data.enums.PredefinedTypes
import com.example.disasterresponseplatform.databinding.ActivityItemBinding
import kotlinx.coroutines.delay
import java.util.logging.Handler

class ActivityAdapter(private val activityList: MutableList<DummyActivity>): RecyclerView.Adapter<ActivityAdapter.ActivityViewHolder>() {

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.example.disasterresponseplatform.data.database

import android.content.Context
import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import com.example.disasterresponseplatform.data.database.need.Need
import com.example.disasterresponseplatform.data.database.need.NeedDao

@Database(entities = [Need::class], version = DatabaseInfo.DATABASE_VERSION, exportSchema = false)
abstract class DarpDB: RoomDatabase() {
abstract val needDao: NeedDao

// it's static object in this way you can call getInstance method without any initialization
companion object{
@Volatile //this makes this field visible to other threads
private var firstInstance: DarpDB? = null

fun getInstance(context: Context): DarpDB {
synchronized(this) {
var instance = firstInstance
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
DarpDB::class.java, DatabaseInfo.DATABASE
)
.allowMainThreadQueries()
.fallbackToDestructiveMigration() // when migrate a new version delete the existing db
.build()
firstInstance = instance
}
return instance
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.disasterresponseplatform.data.database

/**
* This is for holding data in regular way.
*/
class DatabaseInfo {
companion object {
const val DATABASE: String = "DARP_DB"
const val ACTION: String = "ACTION"
const val EMERGENCY: String = "EMERGENCY"
const val EVENT: String = "EVENT"
const val NEED: String = "NEED"
const val RESOURCE: String = "RESOURCE"
const val DATABASE_VERSION: Int = 2 // you need to change that whenever you change any table on DB
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.example.disasterresponseplatform.data.database.need

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.example.disasterresponseplatform.data.database.DatabaseInfo

@Entity(tableName = DatabaseInfo.NEED)
data class Need(
@PrimaryKey(autoGenerate = true)
@ColumnInfo (name = NeedCols.id)
val ID: Int?, // if user does not enter ID, it generates it automatically
@ColumnInfo(name = NeedCols.creatorID)
val creatorID: String,
@ColumnInfo(name = NeedCols.type)
val type: String,
@ColumnInfo(name = NeedCols.subTypeList)
val subType: String,
@ColumnInfo(name = NeedCols.creationTime)
val creationTime: String?,
@ColumnInfo(name = NeedCols.quantity)
val quantity: Int?,
@ColumnInfo(name = NeedCols.location)
val location: String?,
@ColumnInfo(name = NeedCols.urgency)
val urgency: Int?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.disasterresponseplatform.data.database.need

class NeedCols {

companion object{
const val id: String = "id"
const val type: String = "type"
const val subTypeList: String = "subTypeList"
const val creationTime: String = "creationTime"
const val creatorID: String = "creatorID"
const val location: String = "location"
const val quantity: String = "quantity"
const val urgency: String = "urgency"

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.disasterresponseplatform.data.database.need

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.example.disasterresponseplatform.data.database.DatabaseInfo

@Dao
interface NeedDao {
@Insert
suspend fun insertActivation(need: Need)

@Query("SELECT ${NeedCols.location} FROM ${DatabaseInfo.NEED} WHERE ${NeedCols.creatorID} = :creatorID")
fun getLocation(creatorID: String): String
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.disasterresponseplatform.data
package com.example.disasterresponseplatform.data.enums

enum class ActivityEnum(val type: Int) {
Action(1),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.disasterresponseplatform.data.enums

enum class Endpoint(val path: String) {
DATA("joke/any"),
USER("user"),
PRODUCTS("products");
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.disasterresponseplatform.data
package com.example.disasterresponseplatform.data.enums

enum class PredefinedTypes(val type: Int) {
Clothes(1),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.example.disasterresponseplatform.data.enums

enum class RequestType {
GET, POST, PUT, DELETE // Add more HTTP methods as needed
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.disasterresponseplatform.data.enums

enum class Urgency(val type: Int) {
EMERGENCY(0),
CRITICAL(1),
URGENT(2),
HIGH_PRIORITY(3),
NORMAL_PRIORITY(4),
LOW_PRIORITY(5)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.disasterresponseplatform.data.models

import com.example.disasterresponseplatform.data.enums.ActivityEnum
import com.example.disasterresponseplatform.data.enums.PredefinedTypes

class DummyActivity(var activityType: ActivityEnum, var predefinedTypes: PredefinedTypes, var location: String,
var date: String, var reliabilityScale: Double) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.disasterresponseplatform.data.repositories

import com.example.disasterresponseplatform.data.database.need.Need
import com.example.disasterresponseplatform.data.database.need.NeedDao
import javax.inject.Inject

class NeedRepository @Inject constructor(private val needDao: NeedDao) {

suspend fun insertNeed(need: Need){
needDao.insertActivation(need)
}

fun getLocation(creatorID: String): String{
return needDao.getLocation(creatorID)
}

}
Loading

0 comments on commit 5bfc4cf

Please sign in to comment.