Skip to content

Commit

Permalink
Aded RIS (/labelsearch only) to Image Labelling
Browse files Browse the repository at this point in the history
  • Loading branch information
bapspatil committed May 2, 2019
1 parent 2fb4a36 commit f3823f1
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 42 deletions.
31 changes: 18 additions & 13 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,41 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ui.IntroActivity"
android:screenOrientation="portrait"
android:launchMode="singleTop"
android:theme="@style/Theme.Intro">
</activity>
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".ui.AuthActivity"
android:launchMode="singleTop"
android:theme="@style/SplashTheme"
android:screenOrientation="portrait">
android:screenOrientation="portrait"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.IntroActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@style/Theme.Intro" />
<activity
android:name=".ui.CameraActivity"
android:launchMode="singleTop"
android:parentActivityName=".ui.PickerActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Main"
android:parentActivityName=".ui.PickerActivity">
</activity>
android:theme="@style/AppTheme.Main" />
<activity
android:name=".ui.RisActivity"
android:launchMode="singleTop"
android:parentActivityName=".ui.CameraActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Result" />
<activity
android:name=".ui.PickerActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Result"></activity>
android:theme="@style/AppTheme.Result" />

<service
android:name=".firebase.RakeFirebaseMessagingService"
Expand All @@ -54,7 +60,6 @@
<meta-data
android:name="com.google.firebase.ml.vision.DEPENDENCIES"
android:value="ocr,label,barcode" />

<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_app_icon_512" />
Expand Down
36 changes: 36 additions & 0 deletions app/src/main/java/com/bapspatil/rake/adapter/MoreInfoAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.bapspatil.rake.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bapspatil.rake.R
import com.bapspatil.rake.model.RisOutputModel
import kotlinx.android.synthetic.main.item_text.view.*
import org.jetbrains.anko.browse

/*
** Created by Bapusaheb Patil {@link https://bapspatil.com}
*/

class MoreInfoAdapter(private val mContext: Context, private val mRisOutputModel: RisOutputModel) : RecyclerView.Adapter<MoreInfoAdapter.TextViewHolder>() {

inner class TextViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): TextViewHolder {
return TextViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_text, viewGroup, false))
}

override fun onBindViewHolder(viewHolder: TextViewHolder, position: Int) {
val title = mRisOutputModel.titles?.get(position)
val link = mRisOutputModel.links?.get(position)
viewHolder.itemView.textItemTextView.text = title
viewHolder.itemView.textItemTextView.setOnClickListener {
link?.let { it1 -> mContext.browse(it1) }
}
}

override fun getItemCount() = mRisOutputModel.titles!!.size

}
4 changes: 2 additions & 2 deletions app/src/main/java/com/bapspatil/rake/model/RisInputModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package com.bapspatil.rake.model
import com.google.gson.annotations.SerializedName

data class RisInputModel(
@SerializedName("image_url")
var imageUrl: String?
@SerializedName("q")
var query: String?
)
18 changes: 8 additions & 10 deletions app/src/main/java/com/bapspatil/rake/model/RisOutputModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@ package com.bapspatil.rake.model
import com.google.gson.annotations.SerializedName

data class RisOutputModel(
@SerializedName("best_guess")
var bestGuess: String?,
@SerializedName("descriptions")
var descriptions: ArrayList<String?>?,
@SerializedName("buy_link")
var buyLink: List<String?>?,
@SerializedName("images")
var images: List<String?>?,
@SerializedName("links")
var links: ArrayList<String?>?,
var links: List<String?>?,
@SerializedName("shop")
var shop: ArrayList<String?>?,
@SerializedName("similar_images")
var similarImages: ArrayList<String?>?,
var shop: List<String?>?,
@SerializedName("sources")
var sources: ArrayList<String?>?,
var sources: List<String?>?,
@SerializedName("titles")
var titles: ArrayList<String?>?
var titles: List<String?>?
)
33 changes: 33 additions & 0 deletions app/src/main/java/com/bapspatil/rake/ris/RisApiService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.bapspatil.rake.ris

import com.bapspatil.rake.model.RisInputModel
import com.bapspatil.rake.model.RisOutputModel
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST

/*
** Created by Bapusaheb Patil {@link https://bapspatil.com}
*/

interface RisApiService {

@Headers("Content-Type: application/json")
@POST("labelsearch")
fun getRisInfo(@Body risInputModel: RisInputModel): Call<RisOutputModel>

companion object {
const val BASE_URL = "https://ris-app.herokuapp.com/"

fun create(): RisApiService {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
return retrofit.create(RisApiService::class.java)
}
}
}
40 changes: 26 additions & 14 deletions app/src/main/java/com/bapspatil/rake/ui/CameraActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ import com.google.firebase.ml.vision.label.FirebaseVisionImageLabel
import com.google.firebase.ml.vision.text.FirebaseVisionText
import com.google.firebase.storage.FirebaseStorage
import com.google.firebase.storage.StorageReference
import kotlinx.android.synthetic.main.activity_camera.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import org.jetbrains.anko.startActivity
import kotlin.coroutines.CoroutineContext

@SuppressLint("RestrictedApi")
Expand All @@ -56,10 +58,13 @@ class CameraActivity : AppCompatActivity(), CoroutineScope {
private lateinit var globalStorageRef: StorageReference
private var userUid: String? = null
private lateinit var keyFunction: String
private var shouldCallRisApi = false
private var risApiInput = ""

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_camera)
job = Job()

binding.cameraView.requestPermissions(this@CameraActivity)
binding.cameraView.setPermissionsListener(object : CameraKitView.PermissionsListener {
Expand All @@ -72,8 +77,6 @@ class CameraActivity : AppCompatActivity(), CoroutineScope {
}
})

job = Job()

userUid = FirebaseAuth.getInstance().currentUser?.uid.toString()

keyFunction = intent.getStringExtra(Constants.KEY_FUNCTION)
Expand All @@ -94,19 +97,23 @@ class CameraActivity : AppCompatActivity(), CoroutineScope {
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
}
} else {
if (!progressDialog.isShowing) {
progressDialog.setCanceledOnTouchOutside(false)
progressDialog.setMessage(getString(R.string.scanning_image))
progressDialog.setOnCancelListener {
NavUtils.navigateUpFromSameTask(this@CameraActivity)
if (!shouldCallRisApi) {
if (!progressDialog.isShowing) {
progressDialog.setCanceledOnTouchOutside(false)
progressDialog.setMessage(getString(R.string.scanning_image))
progressDialog.setOnCancelListener {
NavUtils.navigateUpFromSameTask(this@CameraActivity)
}
progressDialog.show()
}
progressDialog.show()
}
val image = FirebaseVisionImage.fromBitmap(bitmap)
when (keyFunction) {
Constants.VALUE_RECOGNIZE_TEXT -> recognizeText(image)
Constants.VALUE_SCAN_BARCODE -> scanBarcode(image)
Constants.VALUE_LABEL_IMAGE -> labelImage(image)
val image = FirebaseVisionImage.fromBitmap(bitmap)
when (keyFunction) {
Constants.VALUE_RECOGNIZE_TEXT -> recognizeText(image)
Constants.VALUE_SCAN_BARCODE -> scanBarcode(image)
Constants.VALUE_LABEL_IMAGE -> labelImage(image)
}
} else {
startActivity<RisActivity>(Constants.KEY_LABEL_FOR_RIS to risApiInput)
}
}
}
Expand Down Expand Up @@ -145,6 +152,9 @@ class CameraActivity : AppCompatActivity(), CoroutineScope {
detector.processImage(image)
.addOnSuccessListener { labels ->
updateUIForImageLabeling(labels)
captureFab.setImageResource(R.drawable.ic_search_white_24dp)
shouldCallRisApi = true
risApiInput = labels[0].text
}
.addOnFailureListener { exception ->
Log.d("IMAGE_LABELLING", exception.toString())
Expand Down Expand Up @@ -226,6 +236,8 @@ class CameraActivity : AppCompatActivity(), CoroutineScope {
saveToFirestoreFab.visibility = View.GONE
}
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
shouldCallRisApi = false
risApiInput = ""
}

private fun showPreview(byteArray: ByteArray) {
Expand Down
91 changes: 91 additions & 0 deletions app/src/main/java/com/bapspatil/rake/ui/RisActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.bapspatil.rake.ui

import android.app.ProgressDialog
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NavUtils
import androidx.databinding.DataBindingUtil
import com.bapspatil.rake.R
import com.bapspatil.rake.adapter.MoreInfoAdapter
import com.bapspatil.rake.databinding.ActivityRisBinding
import com.bapspatil.rake.model.RisInputModel
import com.bapspatil.rake.model.RisOutputModel
import com.bapspatil.rake.ris.RisApiService
import com.bapspatil.rake.util.CommonUtils.makeUiLight
import com.bapspatil.rake.util.Constants
import kotlinx.android.synthetic.main.activity_ris.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import org.jetbrains.anko.browse
import org.jetbrains.anko.longToast
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlin.coroutines.CoroutineContext

class RisActivity : AppCompatActivity(), CoroutineScope {
private lateinit var binding: ActivityRisBinding
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main

private val progressDialog: ProgressDialog by lazy {
ProgressDialog(this)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_ris)
job = Job()

makeUiLight()

if (!progressDialog.isShowing) {
progressDialog.setCanceledOnTouchOutside(false)
progressDialog.setMessage("Getting more info...")
progressDialog.setOnCancelListener {
NavUtils.navigateUpFromSameTask(this@RisActivity)
}
progressDialog.show()
}

val labelForRis = intent.getStringExtra(Constants.KEY_LABEL_FOR_RIS)
if (labelForRis != null) {
val risInputModel = RisInputModel(labelForRis)
RisApiService.create()
.getRisInfo(risInputModel)
.enqueue(object : Callback<RisOutputModel> {
override fun onFailure(call: Call<RisOutputModel>, t: Throwable) {
longToast("Failed to fetch your data!")
if (progressDialog.isShowing)
progressDialog.hide()
NavUtils.navigateUpFromSameTask(this@RisActivity)
}

override fun onResponse(call: Call<RisOutputModel>, response: Response<RisOutputModel>) {
if (response.isSuccessful && response.body() != null) {
updateUiWithData(response.body()!!)
if (progressDialog.isShowing)
progressDialog.hide()
}
}
})
}
}

private fun updateUiWithData(risOutputModel: RisOutputModel) {
moreInfoRecyclerView.adapter = MoreInfoAdapter(this, risOutputModel)
googleImagesButton.setOnClickListener {
risOutputModel.images?.get(0)?.let { it1 -> browse(it1) }
}
labelledImagesDashboardButton.setOnClickListener {
browse("https://rake.now.sh/#/dashboard/labelled-images")
}
}

override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}
2 changes: 2 additions & 0 deletions app/src/main/java/com/bapspatil/rake/util/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class Constants {
const val VALUE_SCAN_BARCODE = "VALUE_SCAN_BARCODE"
const val VALUE_LABEL_IMAGE = "VALUE_LABEL_IMAGE"

const val KEY_LABEL_FOR_RIS = "KEY_LABEL_FOR_RIS"

// App keys
const val KEY_PREFERENCE_FIRST_LAUNCH = "KEY_PREFERENCE_FIRST_LAUNCH"
const val KEY_CURRENT_USER_UID = "KEY_CURRENT_USER_UID"
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/drawable/ic_search_white_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
<path android:fillColor="#FFFFFF" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
</vector>
8 changes: 5 additions & 3 deletions app/src/main/res/layout/activity_camera.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
android:keepScreenOn="true"
app:camera_facing="back"
app:camera_flash="auto"
app:camera_imageJpegQuality="100"
app:camera_focus="continuous"
app:camera_imageJpegQuality="100"
app:camera_imageMegaPixels="1.0"
app:camera_permissions="camera" />

Expand Down Expand Up @@ -91,7 +91,8 @@
android:visibility="gone"
app:fabSize="mini"
app:layout_anchor="@id/relativeLayoutContainer"
app:layout_anchorGravity="end|bottom" />
app:layout_anchorGravity="end|bottom"
tools:visibility="visible" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/saveToFirestoreFab"
Expand All @@ -103,7 +104,8 @@
android:visibility="gone"
app:fabSize="mini"
app:layout_anchor="@id/relativeLayoutContainer"
app:layout_anchorGravity="start|bottom" />
app:layout_anchorGravity="start|bottom"
tools:visibility="visible" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/captureFab"
Expand Down
Loading

0 comments on commit f3823f1

Please sign in to comment.