Skip to content

Commit

Permalink
Adds room, workmanager, hilt and retrofit
Browse files Browse the repository at this point in the history
  • Loading branch information
siddheshkothadi committed Aug 3, 2022
1 parent fe4cc31 commit 671dfbe
Show file tree
Hide file tree
Showing 15 changed files with 481 additions and 3 deletions.
35 changes: 33 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}

android {
Expand All @@ -21,7 +23,7 @@ android {

buildTypes {
release {
minifyEnabled false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
Expand Down Expand Up @@ -61,13 +63,18 @@ dependencies {
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"

// extra compose dependencies
implementation "androidx.compose.material:material-icons-extended:$compose_version"
implementation("io.coil-kt:coil-compose:2.0.0-rc02")
implementation "com.airbnb.android:lottie-compose:5.0.3"
implementation "androidx.compose.runtime:runtime-livedata:1.2.0-alpha05"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1"

// accompanist
implementation "com.google.accompanist:accompanist-navigation-animation:0.24.5-alpha"
implementation "com.google.accompanist:accompanist-permissions:0.24.3-alpha"

// splash screen
implementation "androidx.core:core-splashscreen:1.0.0-beta01"

// Timber for logging
Expand All @@ -81,6 +88,30 @@ dependencies {
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"
implementation "androidx.camera:camera-extensions:${camerax_version}"


// mlkit object detection
implementation 'com.google.mlkit:object-detection-custom:17.0.0'

// Retrofit for network requests
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"

// Room
def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"

// Hilt
implementation "com.google.dagger:hilt-android:2.38.1"
kapt "com.google.dagger:hilt-compiler:2.38.1"
implementation "androidx.hilt:hilt-navigation-compose:1.0.0"
kapt "androidx.hilt:hilt-compiler:1.0.0"

// Location
implementation 'com.google.android.gms:play-services-location:19.0.1'

// WorkManager
implementation "androidx.work:work-runtime-ktx:2.7.1"
implementation 'androidx.hilt:hilt-work:1.0.0'
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
package me.siddheshkothadi.autofism3

import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.os.Build
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber
import javax.inject.Inject

@HiltAndroidApp
class FishApplication: Application(), Configuration.Provider {

@Inject
lateinit var uploadWorkerFactory: HiltWorkerFactory

class FishApplication: Application() {
override fun onCreate() {
super.onCreate()

if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"upload_channel",
"Upload",
NotificationManager.IMPORTANCE_HIGH
)

val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(channel)
}
}

override fun getWorkManagerConfiguration(): Configuration {
return Configuration.Builder()
.setWorkerFactory(uploadWorkerFactory)
.build()
}
}
26 changes: 26 additions & 0 deletions app/src/main/java/me/siddheshkothadi/autofism3/database/FishDAO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package me.siddheshkothadi.autofism3.database

import androidx.room.*
import kotlinx.coroutines.flow.Flow
import me.siddheshkothadi.autofism3.model.Fish

@Dao
interface FishDAO {
@Query("SELECT * FROM fishentity")
fun getAll(): Flow<List<FishEntity>>

@Query("SELECT * FROM fishentity")
suspend fun getFishList(): List<FishEntity>

@Query("SELECT * FROM fishentity WHERE imageUri = :imageUri")
suspend fun getByImageUri(imageUri: String): FishEntity

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(fishEntity: FishEntity)

@Delete
suspend fun delete(fishEntity: FishEntity)

@Query("DELETE FROM fishentity")
suspend fun deleteAll()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package me.siddheshkothadi.autofism3.database

import androidx.room.Database
import androidx.room.RoomDatabase

@Database(entities = [FishEntity::class], version = 1, exportSchema = false)
abstract class FishDatabase: RoomDatabase() {
abstract fun fishDAO(): FishDAO
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package me.siddheshkothadi.autofism3.database

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class FishEntity(
@PrimaryKey val imageUri: String,
val longitude: String,
val latitude: String,
val quantity: String,
val timeStamp: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package me.siddheshkothadi.autofism3.database

import androidx.room.PrimaryKey
import me.siddheshkothadi.autofism3.model.Fish

fun FishEntity.toFish(): Fish {
return Fish(
imageUri = imageUri,
longitude = longitude,
latitude = latitude,
quantity = quantity,
timeStamp = timeStamp
)
}

fun Fish.toFishEntity(): FishEntity {
return FishEntity(
imageUri = imageUri,
longitude = longitude,
latitude = latitude,
quantity = quantity,
timeStamp = timeStamp
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package me.siddheshkothadi.autofism3.database

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import me.siddheshkothadi.autofism3.model.Fish
import me.siddheshkothadi.autofism3.network.FileAPI
import me.siddheshkothadi.autofism3.repository.FishRepository
import okhttp3.MultipartBody
import okhttp3.RequestBody
import timber.log.Timber

class FishRepositoryImpl(
private val fishDAO: FishDAO,
private val fileAPI: FileAPI
): FishRepository {
override fun getAllFish(): Flow<List<Fish>> {
return fishDAO.getAll().map {spots ->
spots.map { spot ->
spot.toFish()
}
}
}

override suspend fun getFishList(): List<Fish> {
return fishDAO.getFishList().map {
it.toFish()
}
}

override suspend fun getFishByImageUri(imageUri: String): Fish {
return fishDAO.getByImageUri(imageUri).toFish()
}

override suspend fun insertFish(fish: Fish) {
fishDAO.insert(fish.toFishEntity())
}

override suspend fun deleteFish(fish: Fish) {
fishDAO.delete(fish.toFishEntity())
}

override suspend fun deleteAllFish() {
fishDAO.deleteAll()
}

override suspend fun uploadFishData(
image: MultipartBody.Part,
longitude: RequestBody,
latitude: RequestBody,
quantity: RequestBody,
timestamp: RequestBody
) {
fileAPI.uploadData(image, longitude, latitude, quantity, timestamp)
}

override suspend fun getHistory(): List<Fish> {
return fileAPI.getHistory()
}
}
60 changes: 60 additions & 0 deletions app/src/main/java/me/siddheshkothadi/autofism3/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package me.siddheshkothadi.autofism3.di

import android.content.Context
import androidx.room.Room
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import me.siddheshkothadi.autofism3.FishApplication
import me.siddheshkothadi.autofism3.database.FishDatabase
import me.siddheshkothadi.autofism3.database.FishRepositoryImpl
import me.siddheshkothadi.autofism3.network.FileAPI
import me.siddheshkothadi.autofism3.repository.FishRepository
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create
import javax.inject.Singleton

//const val BASE_URL = "https://file-upload-server.siddheshkothadi.repl.co/"
//const val BASE_URL = "https://autofis-server.siddheshkothadi.repl.co/"
const val BASE_URL = "http://127.0.0.1:5000/"

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Singleton
@Provides
fun provideApplication(@ApplicationContext appContext: Context): FishApplication {
return appContext as FishApplication
}

@Singleton
@Provides
fun provideRetrofit(): FileAPI {
val retrofit = Retrofit
.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()

return retrofit.create(FileAPI::class.java)
}

@Singleton
@Provides
fun provideFishDatabase(appContext: FishApplication): FishDatabase {
return Room.databaseBuilder(
appContext,
FishDatabase::class.java,
"fish_database"
).build()
}

@Singleton
@Provides
fun provideFishRepository(fishDatabase: FishDatabase, fileAPI: FileAPI): FishRepository {
return FishRepositoryImpl(fishDatabase.fishDAO(), fileAPI)
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/me/siddheshkothadi/autofism3/model/Fish.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package me.siddheshkothadi.autofism3.model

data class Fish(
val _id: String = "",
val imageUri: String = "",
val longitude: String,
val latitude: String,
val quantity: String,
val timeStamp: String,
val image_url: String = "",
val name: String = ""
)
26 changes: 26 additions & 0 deletions app/src/main/java/me/siddheshkothadi/autofism3/network/FileAPI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package me.siddheshkothadi.autofism3.network

import kotlinx.coroutines.flow.Flow
import me.siddheshkothadi.autofism3.model.Fish
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.http.GET
import retrofit2.http.Multipart
import retrofit2.http.POST
import retrofit2.http.Part

interface FileAPI {

@Multipart
@POST("/api/upload")
suspend fun uploadData(
@Part image: MultipartBody.Part,
@Part("longitude") longitude: RequestBody,
@Part("latitude") latitude: RequestBody,
@Part("quantity") quantity: RequestBody,
@Part("timestamp") timestamp: RequestBody,
)

@GET("/api/history")
suspend fun getHistory() : List<Fish>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okio.BufferedSink
import java.io.InputStream

class UploadStreamRequestBody(
private val mediaType: String,
private val inputStream: InputStream,
private val onUploadProgress: (Int) -> Unit,
) : RequestBody() {

override fun contentLength(): Long = inputStream.available().toLong()

override fun contentType(): MediaType? = mediaType.toMediaTypeOrNull()

override fun writeTo(sink: BufferedSink) {
val contentLength = inputStream.available().toFloat()
val buffer = ByteArray(DEFAULT_BUFFER_SIZE) // DEFAULT_BUFFER_SIZE constant from kotlin.io.ConstantsKt
inputStream.use { inputStream ->
var uploaded = 0
var read: Int
while (inputStream.read(buffer).also { read = it } != -1) { // Reads the stream until the content ends
sink.write(buffer, 0, read)
uploaded += read
onUploadProgress((100*uploaded/contentLength).toInt())
}
}
}
}
Loading

0 comments on commit 671dfbe

Please sign in to comment.