Room database not working-2 Errors See Description - android

When the app is ran, the following errors occur:
Errors:
C:\Users\John\AndroidStudioProjects\Todoit 2\app\build\tmp\kapt3\stubs\debug\com\example\todoit\data\TodoDao.java:11: error: Not sure how to handle insert method's return type.
public abstract java.lang.Object addTodo(#org.jetbrains.annotations.NotNull()
C:\Users\John\AndroidStudioProjects\Todoit 2\app\build\tmp\kapt3\stubs\debug\com\example\todoit\data\TodoDao.java:13: error: Type of the parameter must be a class annotated with #Entity or a collection/array of it.
kotlin.coroutines.Continuation<? super kotlin.Unit> continuation);
Any help would be greatly appreciated.
Code:
Todo
package com.example.todoit.data
import androidx.room.Entity
import androidx.room.PrimaryKey
#Entity(tableName = "todo_data")
data class Todo (
#PrimaryKey val id: Int,
val title: String,
var isChecked: Boolean = false
)
TodoDao
package com.example.todoit.data
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
#Dao
interface TodoDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addTodo(todo: Todo)
#Query("SELECT * FROM todo_data ORDER BY id ASC")
fun readAllData(): LiveData<List<Todo>>
}
TodoDataBase
package com.example.todoit.data
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
#Database(entities = [Todo::class],version = 1, exportSchema = false)
abstract class TodoDataBase: RoomDatabase() {
abstract fun todoDao(): TodoDao
companion object{
#Volatile
private var INSTANCE: TodoDataBase? = null
fun getDataBase(context: Context):TodoDataBase{
val tempInstance = INSTANCE
if(tempInstance != null){
return tempInstance
}
synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TodoDataBase::class.java,
"todo_database"
).build()
INSTANCE = instance
return instance
}
}
}
}
TodoRepository
package com.example.todoit.data
import androidx.lifecycle.LiveData
class TodoRepository(private val todoDao:TodoDao) {
val readAllData: LiveData<List<Todo>> = todoDao.readAllData()
suspend fun addTodo(todo:Todo) {
todoDao.addTodo(todo)
}
}
TodoViewModel
package com.example.todoit.data
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class TodoViewModel(application: Application) : AndroidViewModel(application) {
private val readAllData: LiveData<List<Todo>>
private val repository: TodoRepository
init {
val todoDao = TodoDataBase.getDataBase(application).todoDao()
repository = TodoRepository(todoDao)
readAllData = repository.readAllData
}
fun addTodoToDataBase(todo: Todo) {
viewModelScope.launch(Dispatchers.IO) {
repository.addTodo(todo)
}
}
}
MainActivity
package com.example.todoit
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.todoit.data.Todo
import com.example.todoit.data.TodoViewModel
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private lateinit var todoAdapter: TodoAdapter
private lateinit var todoViewModel: TodoViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
todoViewModel = ViewModelProvider(this).get(TodoViewModel::class.java)
todoAdapter = TodoAdapter(mutableListOf())
rvTodoItems.layoutManager = LinearLayoutManager(this)
rvTodoItems.adapter = todoAdapter
btnAddTodo.setOnClickListener {
val todoTitle = etTodoTitle.text.toString()
if (todoTitle.isNotEmpty()) {
val todo = Todo(0,todoTitle,false)
etTodoTitle.text.clear()
insertDataToDataBase(todo)
todoAdapter.addTodo(todo)
}
btnDeleteTodo.setOnClickListener {
todoAdapter.deleteDoneTodos()
}
}}
private fun insertDataToDataBase(todo: Todo) {
val todoTitle = etTodoTitle.text.toString()
if(todoTitle.isNotEmpty()) {
//Add data to database
todoViewModel.addTodoToDataBase(todo)
}
}
}
TodoAdapter
package com.example.todoit
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.todoit.data.Todo
import kotlinx.android.synthetic.main.item_todo.view.*
class TodoAdapter(
private val todos: MutableList<Todo>,
) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
return TodoViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_todo,
parent,
false
)
)
}
fun addTodo(todo: Todo) {
todos.add(todo)
notifyItemInserted(todos.size - 1)
}
fun deleteDoneTodos() {
todos.removeAll { todo ->
todo.isChecked
}
notifyDataSetChanged()
}
private fun toggleStrikeThrough(tvTodoTitle: TextView, isChecked: Boolean) {
if (isChecked) {
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG
} else {
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
}
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val curTodo = todos[position]
holder.itemView.apply {
tvTodoTitle.text = curTodo.title
cbDone.isChecked = curTodo.isChecked
toggleStrikeThrough(tvTodoTitle, curTodo.isChecked)
cbDone.setOnCheckedChangeListener { _, isChecked ->
toggleStrikeThrough(tvTodoTitle, isChecked)
curTodo.isChecked = !curTodo.isChecked
}
}
}
override fun getItemCount(): Int {
return todos.size
}
}
Gradle(Module)
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id "kotlin-android-extensions"
}
apply plugin: 'kotlin-kapt'
android {
compileSdk 32
defaultConfig {
applicationId "com.example.todoit"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
//ROOM
def roomVersion = "2.4.2"
implementation 'androidx.room:room-ktx:2.2.1'
kapt "androidx.room:room-compiler:2.2.1"
// Navigation Component
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
// Kotlin components
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5"
}
Gradle(Project)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.2.0' apply false
id 'com.android.library' version '7.2.0' apply false
id 'org.jetbrains.kotlin.android' version '1.5.30' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}

I think you should set the dependencies for room as follows:
def roomVersion = "2.4.2"
implementation "androidx.room:room-ktx:$roomVersion"
kapt "androidx.room:room-compiler:$roomVersion"

Related

Problem with TensorFlow Lite detection Canvas "Custom view Draw is missing constructor"

I'm having troubles with a class inside "utils" package on my Kotlin code
Classic issues I guess, but I have been looking for solutions on forums and nothing works, I'm just trying the bindPreview method with CameraX
This is my main activity
import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.util.Size
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.LifecycleOwner
import com.fablab.tensorflowcamerax.databinding.ActivityMainBinding
import com.fablab.tensorflowcamerax.utils.Draw
import com.google.common.util.concurrent.ListenableFuture
import com.google.mlkit.common.model.LocalModel
import com.google.mlkit.vision.common.InputImage
import com.google.mlkit.vision.objects.ObjectDetection
import com.google.mlkit.vision.objects.ObjectDetector
import com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var objectDetector: ObjectDetector
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
bindPreview(cameraProvider = cameraProvider)
}, ContextCompat.getMainExecutor(this))
val localModel = LocalModel.Builder()
.setAssetFilePath("object_detection.tflite")
// \\assets\object_detection.tflite
.build()
val customObjectDetectorOptions = CustomObjectDetectorOptions.Builder(localModel)
.setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE)
.enableClassification()
.setClassificationConfidenceThreshold(0.5f)
.setMaxPerObjectLabelCount(3)
.build()
objectDetector = ObjectDetection.getClient(customObjectDetectorOptions)
}
#SuppressLint("UnsafeOptInUsageError")
private fun bindPreview (cameraProvider: ProcessCameraProvider) {
val preview = Preview.Builder().build()
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
preview.setSurfaceProvider(binding.previewView.surfaceProvider)
val imageAnalysis = ImageAnalysis.Builder()
.setTargetResolution(Size(1200,720))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this)
) { imageProxy ->
val rotationDegreesValue = imageProxy.imageInfo.rotationDegrees
val image = imageProxy.image
if (image != null) {
val processImage = InputImage.fromMediaImage(image, rotationDegreesValue)
objectDetector
.process(processImage)
.addOnSuccessListener { objects ->
for (i in objects) {
if (binding.parentLayout.childCount > 1) binding.parentLayout.removeViewAt(1)
val context = binding.root.context
val element = Draw(
context = context,
rect = i.boundingBox,
text = i.labels.firstOrNull()?.text ?: "Undefined"
)
binding.parentLayout.addView(element)
}
imageProxy.close()
}.addOnFailureListener {
Log.v("MainActivity", "Error - ${it.message}")
imageProxy.close()
}
}
}
cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview, imageAnalysis)
}
}
My custom view "Draw"
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.view.View
class Draw(context: Context?, var rect: Rect, var text: String): View(context) {
lateinit var boundaryPaint: Paint
lateinit var textPaint: Paint
init {
init()
}
private fun init(){
boundaryPaint = Paint()
boundaryPaint.color = Color.BLACK
boundaryPaint.strokeWidth = 10f
boundaryPaint.style = Paint.Style.STROKE
textPaint = Paint()
textPaint.color = Color.BLACK
textPaint.textSize = 50f
textPaint.style = Paint.Style.FILL
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawText(
text,
rect.centerX().toFloat(),
rect.centerY().toFloat(),
textPaint)
canvas?.drawRect(
rect.left.toFloat(),
rect.top.toFloat(),
rect.right.toFloat(),
rect.bottom.toFloat(),
boundaryPaint
)
}
}
And the gradle (I know there are deprecated dependencies, I deliveratedly choose them because compile and work with the method that I'm replicating)
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
android {
compileSdk 33
//buildToolsVersion "30.0.1"
defaultConfig {
minSdk 21
//noinspection ExpiredTargetSdkVersion
targetSdk 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
aaptOptions {
noCompress "tflite"
}
dataBinding {
enabled = true
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
// Object detection
implementation 'com.google.mlkit:object-detection-custom:16.3.0'
// CameraX
implementation "androidx.camera:camera-camera2:1.3.0-alpha02"
implementation "androidx.camera:camera-lifecycle:1.3.0-alpha02"
implementation "androidx.camera:camera-view:1.3.0-alpha02"
}
The "Draw" class is inside utils package and the IDE gives a warning that says:
"Custom view Draw is missing constructor used by tools: (Context) or (Context,AttributeSet) or (Context,AttributeSet,int)"
I tried with and without declaring context value on the objectDetector for, and nothing happens
I also tried converting to secondary constuctor, but did not working either
The project compiles, when I build an APK and execute the app, I got access to native camera (giving manually hardware permission, but I will work on that detail later) but nothing about object detection and canvas drawing.
Please guide me to find a solution without changing again the dependencies version, and I need to know if the assetFilePath is correct too.
Thank you.

Data isn't updating in Firestore database

My first time asking questions here I think I'm going insane. Working on a school project, I am creating an app like Goodreads, I have recyclerView which lists all the books from database(reading data works fine) and a different fragment where you can write a review for each book. So I have 3 layouts(main_activity layout,review layout and a layout that designs an item for recyclerView).
The problem is when I click save button which is supposed to save a review ni database it does nothing. I have a collection called "books" which has 8 documents and fields such as title,author,rating,image,review. All fields are string types. My rules allow writing and reading data. I have no idea what to do if anyone has better insight I will be really thankful
Main activity:
class MainActivity : AppCompatActivity(),BookRecyclerAdapter.ContentListener {
private lateinit var recyclerAdapter: BookRecyclerAdapter
private val db = Firebase.firestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(layout.activity_main)
val recyclerView = findViewById<RecyclerView>(id.booksList)
db.collection("books")
.get() //da dohvati sve dokumente
.addOnSuccessListener { //unutar ovoga pristup svim podadcima koji su se ucitali
val items: ArrayList<Book> = ArrayList()
for (data in it.documents) { //stvori novu data varijablu za svaki dohvaceni dokument(element?)
val book =
data.toObject(Book::class.java) //sve podatke pretvaramo u model preko toObject u Person
if (book != null) {
book.id = data.id //postavljanje ida
items.add(book) //dodavanje gotovog eprsona u listu
}
}
recyclerAdapter = BookRecyclerAdapter(items, this#MainActivity)
recyclerView.apply {
layoutManager = LinearLayoutManager(this#MainActivity)
adapter = recyclerAdapter
}
}.addOnFailureListener { exception ->
Log.w("MainActivity", "Error getting documents", exception)
}
}
override fun onItemButtonClick(index: Int, item: Book, clickType: ItemClickType) {
if (clickType == ItemClickType.SAVE) {
db.collection("books").document(item.id)
.set(item)
.addOnSuccessListener { Log.d(TAG, "DocumentSnapshot successfully written!") }
.addOnFailureListener { e -> Log.w(TAG, "Error writing document", e) }
}
else if (clickType == ItemClickType.REVIEW) {
val newFragment: Fragment = ReviewFragment()
val transaction: FragmentTransaction? = supportFragmentManager.beginTransaction()
transaction?.replace(R.id.container, newFragment);
transaction?.addToBackStack(null);
transaction?.commit();
}
}
}
BookRecyclerAdapter
package hr.ferit.enasalaj.zavrsni
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
enum class ItemClickType {
SAVE,
REVIEW
}
class BookRecyclerAdapter(
val items:ArrayList<Book>,
val listener: ContentListener,
): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val mainView = LayoutInflater.from(parent.context).inflate(R.layout.recycler_view_books, parent, false)
val reviewView = LayoutInflater.from(parent.context).inflate(R.layout.review, parent, false)
return BookViewHolder(mainView, reviewView)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is BookViewHolder -> {
holder.bind(position, listener, items[position])
}
}
}
override fun getItemCount(): Int {
return items.size
}
class BookViewHolder(val view: View,val review: View): RecyclerView.ViewHolder(view) {
private val bookImage =
view.findViewById<ImageView>(R.id.image)
private val bookAuthor =
view.findViewById<EditText>(R.id.bookAuthor)
private val bookTitle =
view.findViewById<EditText>(R.id.bookTitle)
private val bookRating =
view.findViewById<EditText>(R.id.bookRating)
private val reviewButton =
view.findViewById<Button>(R.id.writeReviewButton)
public val saveButton =
review.findViewById<Button>(R.id.saveButton)
public val bookReview =
review.findViewById<EditText>(R.id.saveReview)
fun bind(
index: Int,
listener: ContentListener,
item: Book,
) {
Glide.with(view.context).load(item.image).into(bookImage)
bookAuthor.setText(item.author)
bookTitle.setText(item.title)
bookRating.setText(item.rating)
bookReview.setText(item.review)
reviewButton.setOnClickListener {
listener.onItemButtonClick(index,item,ItemClickType.REVIEW)
}
saveButton.setOnClickListener{
listener.onItemButtonClick(index,item,ItemClickType.SAVE)
}
}
}
interface ContentListener {
fun onItemButtonClick(index: Int, item: Book, clickType: ItemClickType)
}
}
And here is my gradle file:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.gms.google-services'
}
android {
namespace 'hr.ferit.enasalaj.zavrsni'
compileSdk 32
defaultConfig {
applicationId "hr.ferit.enasalaj.zavrsni"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.firebase:firebase-firestore-ktx:24.4.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
implementation 'com.github.bumptech.glide:glide:4.14.2'
implementation "com.google.firebase:firebase-auth:9.6.1"
implementation 'com.google.firebase:firebase-database:9.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
apply plugin: 'com.google.gms.google-services'
}

Getting Error in building the project using Dao interface and room library

I am stuck with this issue since couple of days. I have gone through many threads where people faced similar issues but did not find any work around on this.
Im getting the error because of using suspend in dao interface but when i remove the error goes away but the app crashes when i try to open it after installation.
I have tried changing the version of room in gradle but that didnot work either.
have a look at my code.
The error message
kotlin.coroutines.Continuation<? super kotlin.Unit> continuation);
NotesDao.kt
package com.example.notes
import androidx.lifecycle.LiveData
import androidx.room.*
#Dao
interface NoteDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(note : Note)
#Delete
suspend fun delete(note : Note)
#Query("Select * from notes_table order by id ASC")
fun getAllNotes() : LiveData <List<Note>>
}
NotesRCAdapter.kt
package com.example.notes
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class NotesRVAdapter(private val context: Context, private val listner : INotesRVAdapter)
: RecyclerView.Adapter<NotesRVAdapter.NoteViewHolder>() {
val allNotes = arrayListOf<Note>()
class NoteViewHolder (itemview : View) : RecyclerView.ViewHolder(itemview){
val textView = itemView.findViewById<TextView>(R.id.tvNote)
val deleteButton = itemview.findViewById<ImageView>(R.id.ivDelete)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
val viewHolder = NoteViewHolder( LayoutInflater.from(context)
.inflate(R.layout.item_note, parent, false))
viewHolder.deleteButton.setOnClickListener{
listner.onItemClicked(allNotes[viewHolder.adapterPosition])
}
return viewHolder
}
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
val currentNote = allNotes[position]
holder.textView.text = currentNote.text
}
override fun getItemCount(): Int {
return allNotes.size
}
fun updateList(newList : List<Note>){
allNotes.clear()
allNotes.addAll(newList)
notifyDataSetChanged()
}
}
interface INotesRVAdapter{
fun onItemClicked(note: Note)
}
NotesDataBase.kt
package com.example.notes
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
#Database(entities = [Note::class], version = 1, exportSchema = false)
abstract class NoteDataBase: RoomDatabase() {
abstract fun getNoteDao(): NoteDao
companion object {
// Singleton prevents multiple instances of database opening at the
// same time.
#Volatile
private var INSTANCE: NoteDataBase? = null
fun getDatabase(context: Context): NoteDataBase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
NoteDataBase::class.java,
"note_database"
).build()
INSTANCE = instance
// return instance
instance
}
}
}
}
//after this we will create our repository
NotesRepository.kt
package com.example.notes
import androidx.lifecycle.LiveData
class NoteRepository(private val noteDao: NoteDao) {
val allNotes : LiveData<List<Note>> = noteDao.getAllNotes()
suspend fun insert(note: Note) {
noteDao.insert(note)
}
suspend fun delete(note: Note){
noteDao.delete(note)
}
}
NoteViewModel.kt
package com.example.notes
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class NoteViewModel(application: Application) : AndroidViewModel(application){
private val repository : NoteRepository
val allNotes : LiveData<List<Note>>
init {
val dao = NoteDataBase.getDatabase(application).getNoteDao()
repository = NoteRepository(dao)
allNotes = repository.allNotes
}
fun deleteNote(note: Note) = viewModelScope.launch(Dispatchers.IO) {
repository.delete(note)
}
fun insertNote(note: Note) = viewModelScope.launch(Dispatchers.IO) {
repository.insert(note)
}
}
Note.kt
package com.example.notes
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
#Entity(tableName = "notes_table") /
class Note(#ColumnInfo(name = "text")val text: String) {
#PrimaryKey(autoGenerate = true) var id = 0
}
MainActivity.kt
package com.example.notes
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.EditText
import android.widget.Toast
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity(), INotesRVAdapter {
lateinit var viewModel: NoteViewModel
private val input = findViewById<EditText>(R.id.etInput)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val RecyclerView = findViewById<RecyclerView>(R.id.recyclerView)
RecyclerView.layoutManager = LinearLayoutManager(this)
val adapter = NotesRVAdapter(this, this)
RecyclerView.adapter = adapter
viewModel = ViewModelProvider(this,
ViewModelProvider.AndroidViewModelFactory.getInstance(application))
.get(NoteViewModel::class.java)
viewModel.allNotes.observe(this, Observer { list ->
list?.let {
adapter.updateList(it)
}
})
}
override fun onItemClicked(note: Note) {
viewModel.deleteNote(note)
Toast.makeText(this,"${note.text} Deleted", Toast.LENGTH_LONG).show()
}
fun submitData(view: View) {
val noteText = input.text.toString()
if (noteText.isNotEmpty()){
viewModel.insertNote(Note(noteText))
Toast.makeText(this,"$noteText Inserted", Toast.LENGTH_LONG).show()
}
}
}
immediate help will be appreciated in understanding the issue and where I went wrong.
Thanks.
Try changing class of entity to data class and also the id field
package com.example.notes
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
#Entity(tableName = "notes_table")
data class Note(
#ColumnInfo(name = "text")val text:
String),
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "text_id")
var id = 0)

etTodoTitle.text not being accessed?

when the app is ran the Edit Text's text is not being accessed and passed for some reason instead this is what it shows in the recycler view and my room database:
https://imgur.com/a/7XjDodL
Sorry if this question doesn't make much sense I didn't really know how to phrase it. Any help is greatly appreciated.
Activity Main
package com.example.todoit
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.todoit.data.Todo
import com.example.todoit.data.TodoDataBase
import com.example.todoit.databinding.ActivityMainBinding
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private lateinit var todoAdapter: TodoAdapter
private lateinit var todoDB: TodoDataBase
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
todoDB = TodoDataBase.getInstance(this)
todoAdapter = TodoAdapter(mutableListOf())
val rvTodoItems = binding.rvTodoItems
val btnAddTodo = binding.btnAddTodo
val btnDeleteTodo = binding.btnDeleteTodo
rvTodoItems.layoutManager = LinearLayoutManager(this)
rvTodoItems.adapter = todoAdapter
btnAddTodo.setOnClickListener {
val todoTitle = binding.etTodoTitle.toString()
if (todoTitle.isNotEmpty()) {
val todo = Todo(null, todoTitle, false)
GlobalScope.launch {
todoDB.todoDao().insertAll(todo)
}
todoAdapter.addTodo(todo)
binding.etTodoTitle.text.clear()
Toast.makeText(this, "Successfully written data", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(this, "There was an error while writing data", Toast.LENGTH_LONG)
.show()
}
}
btnDeleteTodo.setOnClickListener {
todoAdapter.deleteDoneTodos()
Toast.makeText(this, "Selected Todo(s) Deleted", Toast.LENGTH_LONG).show()
}
}
}
TodoAdapter
package com.example.todoit
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.todoit.data.Todo
import kotlinx.android.synthetic.main.item_todo.view.*
class TodoAdapter(
private val todos: MutableList<Todo>,
) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
return TodoViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_todo,
parent,
false
)
)
}
fun addTodo(todo: Todo) {
todos.add(todo)
notifyItemInserted(todos.size - 1)
}
fun deleteDoneTodos() {
todos.removeAll { todo ->
todo.isChecked
}
notifyDataSetChanged()
}
private fun toggleStrikeThrough(tvTodoTitle: TextView, isChecked: Boolean) {
if(isChecked) {
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG
} else {
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
}
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val curTodo = todos[position]
holder.itemView.apply {
tvTodoTitle.text = curTodo.title
cbDone.isChecked = curTodo.isChecked
toggleStrikeThrough(tvTodoTitle, curTodo.isChecked)
cbDone.setOnCheckedChangeListener { _, isChecked ->
toggleStrikeThrough(tvTodoTitle, isChecked)
curTodo.isChecked = !curTodo.isChecked
}
}
}
override fun getItemCount(): Int {
return todos.size
}
}
Gradle(app)
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id "kotlin-android-extensions"
}
apply plugin: 'kotlin-kapt'
android {
compileSdk 32
defaultConfig {
applicationId "com.example.todoit"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures{
viewBinding = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
//ROOM
def roomVersion = "2.4.2"
implementation "androidx.room:room-ktx:$roomVersion"
kapt "androidx.room:room-compiler:$roomVersion"
// Navigation Component
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
// Kotlin components
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5"
}
If you need anymore code then please let me know.
You might want to change the following assignment:
val todoTitle = binding.etTodoTitle.toString()
to this:
val todoTitle = binding.etTodoTitle.text.toString()
Otherwise any new Todo objects created by the onClick will store the View ID of the editText instead of the value you typed inside it...

SMS token faill to responce

I've the below code trying to work with SMS Token, i got the token code, but once i sent it in SMS I got no responce!
MainActivity.kt
package com.sms
import android.app.PendingIntent
import android.content.Intent
import android.os.Bundle
import android.telephony.SmsManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.auth.api.phone.SmsRetrieverClient
import com.sms.ui.theme.SmsTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// val smsManager: SmsManager = SmsManager.getDefault()
val smsManager: SmsManager = getSystemService(SmsManager::class.java)
val appSmsToken = smsManager.createAppSpecificSmsToken(createSmsTokenPendingIntent())
print(appSmsToken)
setContent {
SmsTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Greeting(appSmsToken)
}
}
}
}
private fun createSmsTokenPendingIntent(): PendingIntent? {
return PendingIntent.getActivity(
this, 1234,
Intent(this, SmsTokenResultVerificationActivity::class.java),
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) // setting the mutability flag
}
}
#Composable
fun Greeting(name: String) {
Text(text = "Token is: $name")
}
#Preview(showBackground = true)
#Composable
fun DefaultPreview() {
SmsTheme {
Greeting("Android")
}
}
And SmsTokenResultVerificationActivity.kt is:
package com.sms
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.sms.ui.theme.SmsTheme
class SmsTokenResultVerificationActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SmsTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Greeting("Welcome")
}
}
}
}
#Composable
fun Greeting(name: String) {
Text(text = "hi: $name")
}
}
As another option, I found using SMS retriever API in Android could solve it, but I still interested in using the Token as i want my app to depend on the user device token rather than the app token.
BaseApplication.kt
package com.shishirthedev.smsretriverapi
import android.app.Application
import android.util.Log
import android.widget.Toast
class BaseApplication : Application() {
private val TAG = BaseApplication::class.java.simpleName
override fun onCreate() {
super.onCreate()
// Generate Hash Key >>>>>
val appSignatureHashHelper = AppSignatureHashHelper(this)
Log.e(TAG, "HashKey: " + appSignatureHashHelper.appSignatures[0])
var msg = "HashKey: " + appSignatureHashHelper.appSignatures[0]
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
// Storing data into SharedPreferences
val sharedPreferences = getSharedPreferences("MySharedPref", MODE_PRIVATE)
// Creating an Editor object to edit(write to the file)
val myEdit = sharedPreferences.edit()
// Storing the key and its value as the data fetched from edittext
myEdit.putString("token", appSignatureHashHelper.appSignatures[0])
// myEdit.putInt("age", age.getText().toString().toInt())
// Once the changes have been made,
// we need to commit to apply those changes made,
// otherwise, it will throw an error
myEdit.commit()
}
}
AppSignatureHashHelper.kt
package com.shishirthedev.smsretriverapi
import android.annotation.TargetApi
import android.content.Context
import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.util.Base64
import android.util.Log
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.*
class AppSignatureHashHelper(context: Context?) :
ContextWrapper(context) {// Get all package details
/**
* Get all the app signatures for the current package
*
* #return
*/
val appSignatures: ArrayList<String>
get() {
val appSignaturesHashs = ArrayList<String>()
try {
// Get all package details
val packageName = packageName
val packageManager = packageManager
val signatures = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
packageManager.getPackageInfo(
packageName,
PackageManager.GET_SIGNING_CERTIFICATES
).signingInfo.apkContentsSigners
} else {
TODO("VERSION.SDK_INT < P")
}
for (signature in signatures) {
val hash = hash(packageName, signature.toCharsString())
if (hash != null) {
appSignaturesHashs.add(String.format("%s", hash))
}
}
} catch (e: Exception) {
Log.e(TAG, "Package not found", e)
}
return appSignaturesHashs
}
companion object {
val TAG = AppSignatureHashHelper::class.java.simpleName
private const val HASH_TYPE = "SHA-256"
const val NUM_HASHED_BYTES = 9
const val NUM_BASE64_CHAR = 11
#TargetApi(19)
private fun hash(packageName: String, signature: String): String? {
val appInfo = "$packageName $signature"
try {
val messageDigest = MessageDigest.getInstance(HASH_TYPE)
messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8))
var hashSignature = messageDigest.digest()
// truncated into NUM_HASHED_BYTES
hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES)
// encode into Base64
var base64Hash =
Base64.encodeToString(hashSignature, Base64.NO_PADDING or Base64.NO_WRAP)
base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR)
return base64Hash
} catch (e: NoSuchAlgorithmException) {
Log.e(TAG, "No Such Algorithm Exception", e)
}
return null
}
}
}
SMSReceiver.kt`
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.api.Status
import java.util.regex.Pattern
class SMSReceiver : BroadcastReceiver() {
private var otpListener: OTPReceiveListener? = null
fun setOTPListener(otpListener: OTPReceiveListener?) {
this.otpListener = otpListener
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == SmsRetriever.SMS_RETRIEVED_ACTION) {
val extras = intent.extras
val status = extras!![SmsRetriever.EXTRA_STATUS] as Status?
when (status!!.statusCode) {
CommonStatusCodes.SUCCESS -> {
val sms = extras[SmsRetriever.EXTRA_SMS_MESSAGE] as String?
sms?.let {
// val p = Pattern.compile("[0-9]+") check a pattern with only digit
val p = Pattern.compile("\\d+")
val m = p.matcher(it)
if (m.find()) {
val otp = m.group()
if (otpListener != null) {
otpListener!!.onOTPReceived(otp)
}
}
}
}
}
}
}
interface OTPReceiveListener {
fun onOTPReceived(otp: String?)
}
}
MainActivity.kt
package com.shishirthedev.smsretriverapi
import android.content.IntentFilter
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.shishirthedev.smsretriverapi.SMSReceiver.OTPReceiveListener
class MainActivity : AppCompatActivity() {
private var intentFilter: IntentFilter? = null
private var smsReceiver: SMSReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var token = findViewById<TextView>(R.id.textView)
// Retrieving the value using its keys the file name
// must be same in both saving and retrieving the data
val sh = getSharedPreferences("MySharedPref", MODE_PRIVATE)
// The value will be default as empty string because for
// the very first time when the app is opened, there is nothing to show
val t = sh.getString("token", "")
// val a = sh.getInt("age", 0)
// We can then use the data
token.text = t
// age.setText(a.toString())
// Init Sms Retriever >>>>
initSmsListener()
initBroadCast()
}
private fun initBroadCast() {
intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
smsReceiver = SMSReceiver()
smsReceiver?.setOTPListener(object : OTPReceiveListener {
override fun onOTPReceived(otp: String?) {
showToast("OTP Received: $otp")
}
})
}
private fun initSmsListener() {
val client = SmsRetriever.getClient(this)
client.startSmsRetriever()
}
override fun onResume() {
super.onResume()
registerReceiver(smsReceiver, intentFilter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(smsReceiver)
}
override fun onDestroy() {
super.onDestroy()
smsReceiver = null
}
private fun showToast(msg: String?) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
}
}
manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.shishirthedev.smsretriverapi">
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.SmsRetriverAPi">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
build.gradle (Module)
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.shishirthedev.smsretriverapi"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.gms:play-services-auth:19.0.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.5.0'
}
``build.gradle (Project)`
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.4.10"
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Credit goes to
SHISHIR

Categories

Resources