i'll Check id's and Everything Was Right!! but I don't know what is the problem.
errors :
Unresolved reference: synthetic
Unresolved reference: btnLogin
Unresolved reference: btnSignUp
Unresolved reference: etEmailAddress
Unresolved reference: etPassword
My LoginActivity
class LoginActivity : AppCompatActivity() {
lateinit var firebaseAuth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
firebaseAuth = FirebaseAuth.getInstance()
btnLogin.setOnClickListener {
login()
}
btnSignUp.setOnClickListener {
val intent = Intent(this, SignupActivity::class.java)
startActivity(intent)
finish()
}
}
private fun login(){
val email = etEmailAddress.text.toString()
val password = etPassword.text.toString()
if (email.isBlank() || password.isBlank()) {
Toast.makeText(this, "Email/password cannot be empty", Toast.LENGTH_SHORT).show()
return
}
firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this){
if(it.isSuccessful){
Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
else{
Toast.makeText(this, "Authentication Failed", Toast.LENGTH_SHORT).show()
}
}
}
}
My AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
<application
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/AppThemeNoActionBar">
<activity android:name=".activities.ProfileActivity"/>
<activity android:name=".activities.ResultActivity" />
<activity
android:name=".activities.QuestionActivity"
android:theme="#style/AppTheme" />
<activity android:name=".activities.LoginActivity" />
<activity android:name=".activities.SignupActivity" />
<activity android:name=".activities.LoginIntro" />
<activity android:name=".activities.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
my Build.Gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 32
defaultConfig {
applicationId "com.cheezycode.quizzed"
minSdkVersion 21
targetSdkVersion 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'
}
}
namespace 'com.cheezycode.quizzed'
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.firebase:firebase-auth:19.3.2'
implementation 'com.google.firebase:firebase-firestore:22.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.google.code.gson:gson:2.8.6'
}
Try this once-
You missed the initialization.
Suppose you don't want to do initialization use View binding
USING VIEW BINDING AS PER your gradle use
class LoginActivity : AppCompatActivity() {
lateinit var firebaseAuth: FirebaseAuth
private var _binding: ActivityLoginBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
firebaseAuth = FirebaseAuth.getInstance()
binding.btnLogin.setOnClickListener {
login()
}
binding.btnSignUp.setOnClickListener {
val intent = Intent(this, SignupActivity::class.java)
startActivity(intent)
finish()
}
}
private fun login(){
val email = binding.etEmailAddress.text.toString()
val password = binding.etPassword.text.toString()
if (email.isBlank() || password.isBlank()) {
Toast.makeText(this, "Email/password cannot be empty", Toast.LENGTH_SHORT).show()
return
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
Option 2-
class LoginActivity : AppCompatActivity() {
lateinit var firebaseAuth: FirebaseAuth
private var btnLogin: Button? = null
private var btnSignUp: Button? = null
private var etEmailAddress: EditText? = null
private var etPassword: EditText? = null
lateinit var firebaseAuth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
firebaseAuth = FirebaseAuth.getInstance()
btnLogin = findViewById(R.id.btnLogin)
btnSignUp = findViewById(R.id.btnSignUp)
etEmailAddress = findViewById(R.id.etEmailAddress)
etPassword = findViewById(R.id.etPassword)
btnLogin?.setOnClickListener {
login()
}
btnSignUp?.setOnClickListener {
val intent = Intent(this, SignupActivity::class.java)
startActivity(intent)
finish()
}
}
private fun login() {
val email = etEmailAddress?.text.toString()
val password = etPassword?.text.toString()
if (email.isBlank() || password.isBlank()) {
Toast.makeText(this, "Email/password cannot be empty", Toast.LENGTH_SHORT).show()
return
}
firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this) {
if (it.isSuccessful) {
Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
} else {
Toast.makeText(this, "Authentication Failed", Toast.LENGTH_SHORT).show()
}
}
}
Related
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'
}
I have used phone authentication in my app. While authenticating with phone number which is in same mobile it fails and show error for null pointer exception of Realtime database, but while authenticating with phone number which is in another phone and app in another phone it works perfectly. Why it fails for phone number in same mobile containing app?
Otpverify.kt
package com.bookqueen.bookqueen.Activity
class OtpVerfiy : AppCompatActivity() {
lateinit var auth: FirebaseAuth
lateinit var storedVerificationId: String
lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
private lateinit var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
lateinit var verify: Button
lateinit var resendotp: TextView
lateinit var numbertext: TextView
lateinit var progressBar: ProgressBar
lateinit var database: FirebaseDatabase
lateinit var databaseReference: DatabaseReference
lateinit var number: String
lateinit var otp: EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_otp_verfiy)
auth = FirebaseAuth.getInstance()
verify = findViewById(R.id.btnverify)
resendotp = findViewById(R.id.resendotp)
progressBar = findViewById(R.id.progressBar)
numbertext = findViewById(R.id.intnumber)
otp = findViewById(R.id.edtotp)
progressBar.visibility = View.GONE
database = FirebaseDatabase.getInstance()
databaseReference = database.getReference("Users")
val mobileNumber = intent.getStringExtra("mobilenumber")
number = "+91" + mobileNumber.toString().trim()
numbertext.text = number
verify.setOnClickListener {
//val otp = findViewById<EditText>(R.id.edtotp).text.toString().trim()
if (TextUtils.isEmpty(otp.text.toString())) {
otp.error = getString(R.string.enterotp)
} else if (otp.length() > 0 || otp.length() == 4) {
progressBar.visibility = View.VISIBLE
val credential: PhoneAuthCredential = PhoneAuthProvider.getCredential(
storedVerificationId.toString(), otp.text.toString().trim()
)
signInWithPhoneAuthCredential(credential)
} else {
Toast.makeText(this, getString(R.string.invalidotp), Toast.LENGTH_SHORT).show()
progressBar.visibility = View.GONE
}
}
resendotp.setOnClickListener {
resendcodeforverification(number, resendToken)
Toast.makeText(this, getString(R.string.otpsent), Toast.LENGTH_SHORT).show()
}
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
startActivity(Intent(applicationContext, MainActivity::class.java))
finish()
}
override fun onVerificationFailed(e: FirebaseException) {
Toast.makeText(applicationContext, getString(R.string.verificationfailed),
Toast.LENGTH_LONG).show()
}
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
storedVerificationId = verificationId
resendToken = token
}
}
sendVerificationcode(number)
}
private fun sendVerificationcode(number: String) {
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(number)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(callbacks)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private fun resendcodeforverification(
phone: String,
token: PhoneAuthProvider.ForceResendingToken?
) {
val option = PhoneAuthOptions.newBuilder()
.setPhoneNumber(phone)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(callbacks)
.setForceResendingToken(token!!)
.build()
PhoneAuthProvider.verifyPhoneNumber(option)
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
auth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
Toast.makeText(this, getString(R.string.signinsuccess),
Toast.LENGTH_SHORT).show()
databaseReference.orderByChild("Phone").equalTo(number)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.value != null) {
startActivity(
Intent(
applicationContext,
MainActivity::class.java
)
)
progressBar.visibility = View.GONE
finish()
} else {
startActivity(
Intent(
applicationContext,
SaveProfile::class.java
)
)
progressBar.visibility = View.GONE
finish()
}
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(this#OtpVerfiy, error.message, Toast.LENGTH_SHORT)
.show()
}
})
} else {
if (task.exception is FirebaseAuthInvalidCredentialsException) {
Toast.makeText(this, getString(R.string.invalidotp),
Toast.LENGTH_SHORT).show()
progressBar.visibility = View.GONE
}
}
}
.addOnFailureListener { e ->
Toast.makeText(this, e.message.toString(), Toast.LENGTH_SHORT).show()
progressBar.visibility = View.GONE
}
}
}
Error Message
2021-11-19 08:58:35.920 26039-26039/com.bookqueen.bookqueen
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.bookqueen.bookqueen, PID: 26039
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.bookqueen.bookqueen/com.bookqueen.bookqueen
.Activity.MainActivity}: java.lang.NullPointerException at
android.app.ActivityThread.performLaunchActivity
(ActivityThread.java:3534) at
android.app.ActivityThread.handleLaunchActivity
(ActivityThread.java:3689)at
android.app.servertransaction.LaunchActivityItem.execute
(LaunchActivityItem.java:83) at
android.app.servertransaction.TransactionExecutor.executeCallbacks
(TransactionExecutor.java:140)at
android.app.servertransaction.TransactionExecutor.execute
(TransactionExecutor.java:100)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2239)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:227)
at android.app.ActivityThread.main(ActivityThread.java:7822)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run
(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1026)
Caused by: java.lang.NullPointerException at
com.bookqueen.bookqueen.Activity.MainActivity
.onCreate(MainActivity.kt:40)
at android.app.Activity.performCreate(Activity.java:7969)
at android.app.Activity.performCreate(Activity.java:7958)
at android.app.Instrumentation.callActivityOnCreate
(Instrumentation.java:1306)
at android.app.ActivityThread.performLaunchActivity
(ActivityThread.java:3505)
build.gradle(:app)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.bookqueen.bookqueen"
minSdkVersion 18
targetSdkVersion 30
versionCode 1
versionName "1.0"
multiDexEnabled true
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
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
implementation 'com.google.firebase:firebase-auth:21.0.1'
implementation 'com.google.firebase:firebase-analytics-ktx:19.0.0'
implementation 'com.google.firebase:firebase-database-ktx:20.0.1'
implementation 'com.google.firebase:firebase-firestore-ktx:23.0.3'
implementation 'com.google.firebase:firebase-storage-ktx:20.0.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//material design
implementation 'com.google.android.material:material:1.5.0-alpha01'
// Import the BoM for the Firebase platform
implementation platform('com.google.firebase:firebase-bom:28.3.0')
// Declare the dependency for the Firebase Authentication library
// When using the BoM, you don't specify versions in Firebase library
dependencies
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.google.android.material:material:1.3.0-alpha03'
implementation 'de.hdodenhof:circleimageview:3.1.0'
implementation 'com.github.smarteist:autoimageslider:1.4.0'
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
}
I have created a Sales Order menu, the menu uses the Activity and Fragment files,
The problem is when I display the Customer List page to find customer data that will be used on the SalesOrder page (Create Data tab (use Fragment))
CustomerList page not closed,
Here's my code
First run show
enter image description here
Then I clik Sales Order show like this, its file SalesOrderActivity.kt
Page SalesOrder use TabLayout and Fragment , ie (fragment for Create Data and Fragment List Data)
enter image description here
File SalesOrderActivity.kt
class SalesOrderActivity : AppCompatActivity() {
lateinit var viewPager : ViewPager
lateinit var tabs : TabLayout
private var appContext: Context? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sales_order)
CommonCtx.setViewXml2(contentView)
setSupportActionBar(findViewById(R.id.my_toolbar))
supportActionBar!!.title = "Sales Order"
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
viewPager = findViewById(R.id.viewPager)
tabs = findViewById(R.id.tabs)
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
val position = tab?.position
if (position == 1) {
println("get selected")
}
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
appContext = this
CommonCtx.setActivity(this)
setUpTabs()
}
//SHOW FRAGMENT CREATE DATA AND LIST DATA
private fun setUpTabs(){
val adapter = com.myapp.sfa.adapter.ViewPagerAdapter(supportFragmentManager)
adapter.addFragment(SalesOrderCreateDataFragment(), "Create Data")
adapter.addFragment(CustomerListDataFragment(), "List Data")
viewPager.adapter = adapter
tabs.setupWithViewPager(viewPager)
setupTabIcons()
}
private fun setupTabIcons() {
tabs.getTabAt(0)!!.setIcon(tabIcons.get(0))
tabs.getTabAt(1)!!.setIcon(tabIcons.get(1))
}
private val tabIcons = intArrayOf(
R.drawable.add_sign,
R.drawable.list_48
)
override fun onSupportNavigateUp(): Boolean {
finish()
return true
}
}
in page Sales Order I used fragment for show tab Create Data and List Data
this
file SalesOderCreateDataFragment.kt
class SalesOrderCreateDataFragment : Fragment() {
private var appContext: Context? = null
private lateinit var txtvCustId : TextView
public lateinit var edtCustCode : EditText
private lateinit var btnCustomer : Button
lateinit var DBHelper : DBHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
appContext = this.getActivity()
DBHelper = DBHelper(appContext!!))
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_sales_order_create_data,container,false)
txtvCustId = view.findViewById<TextView>(R.id.txtvCustId)
edtCustCode = view.findViewById<EditText>(R.id.edtCustCode)
btnCustomer = view.findViewById(R.id.btnCustomer)
btnCustomer.setOnClickListener {
showCustomer()
}
appContext = this.getActivity()
return view
}
//SHOW LIST CUSTOMER event clik Cust. Code
fun showCustomer() {
val intent = Intent(this.getActivity(), CustomerListActivity::class.java)
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
CommonCtx.getContext().startActivity(intent)
CustomerListActivity().finish()
}
fun getCustomer(idCustomer: String){
var customerPojo = CustomerPojo()
customerPojo= SQLCustomer().getCustomerById(idCustomer)
}
}
while I click button Cust Code
enter image description here
Will show page CustomerListActivity, like this picture
Code in Cust code event
enter image description here
File CustomerListActivity.kt
class CustomerListActivity : AppCompatActivity() {
private lateinit var recyclerView : RecyclerView
lateinit var DBHelper : DBHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_customer_list)
setSupportActionBar(findViewById(R.id.my_toolbar))
supportActionBar!!.title = "Customer List"
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
recyclerView =findViewById(R.id.recyclerView)
DBHelper = DBHelper(applicationContext)//this)
//get data customer in database local
var listCustomerPojo : MutableList<CustomerPojo> = ArrayList()
listCustomerPojo = SQLCustomer().getCustomerList()
//show data customer in Recycle Card View
showListDataToRecycleCardView(listCustomerPojo);
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main, menu)
val searchItem = menu.findItem(R.id.menu_search)
if(searchItem != null){
val searchView = searchItem.actionView as SearchView
val editext = searchView.findViewById<EditText>
(androidx.appcompat.R.id.search_src_text)
editext.hint = "Search here..."
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
var listCustomerPojo: ArrayList<CustomerPojo> = ArrayList()
if (newText!!.isNotEmpty()) {
val search = newText.toLowerCase()
listCustomerPojo = SQLCustomer().getCustomerByName(newText)
}
showListDataToRecycleCardView(listCustomerPojo);
return true
}
})
}
return super.onCreateOptionsMenu(menu)
}
fun showListDataToRecycleCardView(listCustomerPojo: MutableList<CustomerPojo>){
var customerListDC = arrayListOf<CustomerDataModel>()
for (i in 0 until listCustomerPojo.size) {
var custPojo: CustomerPojo = listCustomerPojo[i]
val cdm = CustomerDataModel(R.drawable.shop_on_ballon_36,
custPojo.custId.toString(),
custPojo.custCode.toString(),
custPojo.custName.toString(),
custPojo.address.toString())
customerListDC.add(cdm)
}
val recyclerAdapter = CustomerListRecyclerAdapter(customerListDC)
recyclerView.apply {
adapter = recyclerAdapter
addItemDecoration(DividerItemDecoration(CommonCtx.getContext(),
DividerItemDecoration.VERTICAL))
setHasFixedSize(true)
}
}
override fun onSupportNavigateUp(): Boolean {
finish()
return true
}
}
file CustomerListRecyclerAdapter.kt
class CustomerListRecyclerAdapter(private var customerListData: ArrayList<CustomerDataModel>)
: RecyclerView.Adapter<CustomerListRecyclerAdapter.ViewHolder>(){
var appContext: Context? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.recycler_customer_list, parent, false)
appContext = parent.context
return ViewHolder(view)
}
override fun getItemCount(): Int = customerListData.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val movie = customerListData[position]
holder.bind(movie)
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val intent: Intent? = null
init {
itemView.setOnClickListener {
var textvCustId = itemView.findViewById<TextView>(R.id.textvCustId)
var textvCustName = itemView.findViewById<TextView>(R.id.textvCustName)
}
}
fun bind(model: CustomerDataModel) {
var imgViewIcon = itemView.findViewById<ImageView>(R.id.imgViewIcon)
var textvCustId = itemView.findViewById<TextView>(R.id.textvCustId)
var textvCustCode = itemView.findViewById<TextView>(R.id.textvCustCode)
var textvCustName = itemView.findViewById<TextView>(R.id.textvCustName)
var textvAddress = itemView.findViewById<TextView>(R.id.textvAddress)
var btnCreateSO = itemView.findViewById<Button>(R.id.btnCreateSO)
var btnCreateSR = itemView.findViewById<Button>(R.id.btnCreateSR)
imgViewIcon.setImageResource(model.iconPict)
textvCustId.text = model.custId
textvCustCode.text = model.custCode
textvCustName.text = model.custName
textvAddress.text = model.address
textvCustId.setVisibility(View.INVISIBLE)
btnCreateSO.setOnClickListener {
SalesOrderCreateDataFragment().getCustomer(textvCustId.text.toString())
}
}
}//end class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
File CommonCtx.kt
#SuppressLint("StaticFieldLeak")
abstract class CommonCtx {
companion object {
#Volatile
private lateinit var appContext : Context
private lateinit var mainActivity : Activity
private lateinit var myActivity : Activity
private lateinit var myView : View
private lateinit var myView2 : View
private lateinit var myView3 : View
private lateinit var myContainer: ViewGroup
fun setContext(context: Context) {
appContext = context
}
fun getFilesDir():String {
return appContext.filesDir.absolutePath
}
fun getOpenFileInput(fileName : String): FileInputStream {
return appContext.openFileInput(fileName)
}
fun getOpenFileOutput(fileName : String): FileOutputStream {
return appContext.openFileOutput(fileName, MODE_PRIVATE)
}
fun getContext():Context{
return appContext
}
fun getContext2():Context{
return appContext.applicationContext
}
fun setMainActivity(activity: Activity) {
mainActivity = activity
}
fun getMainActivity():Activity{
return mainActivity
}
fun setActivity(activity: Activity) {
myActivity = activity
}
fun getActivity():Activity{
return myActivity
}
fun setViewXml(view : View) {
myView = view
}
fun getViewXml():View{
return myView
}
fun setViewXml2(view: View?) {
if (view != null) {
myView2 = view
}
}
fun getViewXml2():View{
return myView2
}
fun setViewXml3(view: View?) {
if (view != null) {
myView3 = view
}
}
fun getViewXml3():View{
return myView3
}
fun setContainer(container : ViewGroup) {
myContainer = container
}
fun getContainer():ViewGroup{
return myContainer
}
}
}
File AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myapp.sfa">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:networkSecurityConfig="#xml/network_security_config"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.MyAppSFA">
<activity android:name=".view.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.view.NetworkSettingActivity"
android:screenOrientation="portrait" />
<activity android:name=".ui.view.salesman.SalesmanProfileActivity"
android:screenOrientation="portrait" />
<activity android:name=".ui.view.sales.SalesOrderActivity"
android:launchMode="singleTop"/>
<activity android:name=".ui.view.sales.SalesReturnActivity"/>
<activity android:name=".view.ui.customer.CustomerActivity" />
<activity android:name=".view.ui.list.CustomerListActivity"
android:noHistory="true"/>
<activity android:name=".view.ui.list.ProductItemListActivity" />
</application>
</manifest>
Problem , while I click button Create SO in page CustomerListActivity
Page CustomerListActivity is not Closed and back to Page SalesOrderActivity
Thanks
enter image description here
in this code, file CustomerListRecyclerAdapter.kt
is not working, CustomerListActivity.kt not close
btnCreateSO.setOnClickListener {
SalesOrderCreateDataFragment().getCustomer(textvCustId.text.toString())
}
this is my file build.gradle(:app)
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.myapp.sfa"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
multiDexEnabled true
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'
}
buildFeatures {
viewBinding true
}
dataBinding {
enabled = true
}
sourceSets {
main {
res.srcDirs = [
'src/main/res',
'src/main/res/layout',
'src/main/res/layout/fragments',
'src/main/res/layout/salesaction',
'src/main/res/layout/salesman',
'src/main/res/layout/setting',
'src\\main\\res', 'src\\main\\res\\layout\\itemrecycler', 'src\\main\\res\\layout\\product', 'src\\main\\res\\layout\\customer'
]
}
//debug {
// res.srcDirs = ['resources/debug']
//}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.anko:anko:0.10.8"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
implementation "com.squareup.retrofit2:converter-moshi:2.4.0"
implementation 'com.squareup.okhttp3:logging-interceptor:4.4.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'androidx.lifecycle:lifecycle-common:2.2.0'
implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0'
implementation 'android.arch.lifecycle:extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
implementation "androidx.viewpager:viewpager:1.0.0"
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.appcompat:appcompat:1.3.0-rc01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation "org.jetbrains.kotlin:kotlin-test-
junit:$kotlin_version"
}
any other ideas, should i change the way to display the Customer list?
Thanks
i have add code (itemView.context as Activity).finish() in CustomerListRecycleAdapter.kt
btnCreateSO.setOnClickListener {
SalesOrderActivity().selectedTabForUpdate(textvCustId.text.toString())
(itemView.context as Activity).finish()
}
and this work, Customer List close
Thanks all
I'm new to android development and I'm trying to create a notification which pops up according to sensor data but before doing this I wanted to get a notification when I open the app(just to check whether the notification I created is working as I expected or not). I've tried running the code but I'm not getting any notification
Here's the main Activity
package com.example.test
import android.app.Notification.PRIORITY_DEFAULT
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT
import androidx.media.app.NotificationCompat
import android.app.PendingIntent
import android.graphics.BitmapFactory
import android.widget.RemoteViews
import com.google.firebase.database.*
import com.jjoe64.graphview.GraphView
import com.jjoe64.graphview.GridLabelRenderer
import com.jjoe64.graphview.Viewport
import com.jjoe64.graphview.series.DataPoint
import com.jjoe64.graphview.series.LineGraphSeries
import java.lang.System.currentTimeMillis
import android.app.NotificationChannel
import android.app.NotificationManager
class MainActivity : AppCompatActivity() {
lateinit private var firebasedatabase: FirebaseDatabase
lateinit private var databaseReference: DatabaseReference
lateinit private var dbref : DatabaseReference
private var channelId : String = "12345"
fun notification(notificationManager : NotificationManager, description : String)
{
val intent = Intent(this, notification::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val contentView = RemoteViews(packageName, R.layout.activity_notification)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(channelId, description, NotificationManager.IMPORTANCE_HIGH)
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.GREEN
notificationChannel.enableVibration(false)
notificationManager.createNotificationChannel(notificationChannel)
val builder = androidx.core.app.NotificationCompat.Builder(this, channelId)
.setContent(contentView)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
notificationManager.notify(1234, builder.build())
}
else{
val builder = androidx.core.app.NotificationCompat.Builder(this)
.setContent(contentView)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
notificationManager.notify(1234, builder.build())
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
firebasedatabase = FirebaseDatabase.getInstance();
databaseReference = firebasedatabase.getReference("temp")
dbref = firebasedatabase.getReference("humidity")
val temp_graph : GraphView = findViewById(R.id.Temp)
//Basic Config of Graph
temp_graph.title = "TEMPERATURE"
val viewport :Viewport = temp_graph.viewport
viewport.setScalable(true)
viewport.setScrollable(true)
viewport.setScalableY(true)
viewport.setScrollableY(true)
viewport.setMinX(0.0)
viewport.setMaxX(10.0)
val gridLabel: GridLabelRenderer = temp_graph.gridLabelRenderer
gridLabel.horizontalAxisTitle = "Time"
// gridLabel.verticalAxisTitle = "Temp."
// val series = LineGraphSeries(
// arrayOf(
// DataPoint(0.0, 1.0), DataPoint(10.0, 5.0), DataPoint(
// 20.0,
// 10.0
// )
// )
// );
// temp_graph.addSeries(series)
var count : Double = 0.0
val series = LineGraphSeries(arrayOf<DataPoint>())
series.setColor(Color.GREEN)
val series2 = LineGraphSeries(arrayOf<DataPoint>())
temp_graph.addSeries(series)
temp_graph.addSeries(series2)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val description = "Test notification"
notification(notificationManager, description)
databaseReference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val value = dataSnapshot.getValue(Float::class.java)
println(value)
val time = currentTimeMillis()
series.appendData(value?.toDouble()?.let { DataPoint(count, it) }, true, 40)
count += 1;
}
override fun onCancelled(databaseError: DatabaseError) {
Toast.makeText(this#MainActivity, "Error fetching data", Toast.LENGTH_LONG)
.show()
}
})
var c2 : Double = 0.0
dbref.addValueEventListener(object : ValueEventListener{
override fun onDataChange(dataSnapshot: DataSnapshot) {
val value = dataSnapshot.getValue(Float::class.java)
println(value)
val time = currentTimeMillis()
series2.appendData(value?.toDouble()?.let { DataPoint(c2, it) }, true, 40)
c2 += 1;
}
override fun onCancelled(databaseError: DatabaseError) {
Toast.makeText(this#MainActivity, "Error fetching data", Toast.LENGTH_LONG)
.show()
}
})
}
}
Here's the app gradle :
plugins {
id 'com.android.application'
id 'kotlin-android'
}
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.example.test"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
multiDexEnabled true
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 fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.core:core:1.5.0#aar'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation("com.android.volley:volley:1.1.1")
implementation "com.google.firebase:firebase-database:11.8.0"
implementation "com.google.firebase:firebase-core:11.8.0"
implementation "com.google.firebase:firebase-storage:11.8.0"
implementation "com.google.firebase:firebase-auth:11.8.0"
implementation 'com.firebaseui:firebase-ui-database:3.2.2'
implementation platform('com.google.firebase:firebase-bom:28.0.1')
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.jjoe64:graphview:4.2.2'
implementation 'com.android.support:multidex:1.0.3'
}
Here's the notification xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".notification">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temperature Value Exceeded "
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Here's the manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.test">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
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.Test"
android:usesCleartextTraffic="true"
tools:targetApi="m">
<activity android:name=".notification2"></activity>
<activity android:name=".notification"></activity>
<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>
Please help me out.. Thanks in Advance :)
For notifications, you need a class that extrend BroadcastReceiver().
Example AlarmReceiver class:
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(ctx: Context, intent: Intent) {
val notificationManager = ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationChannelId = "MY_APP_NAME_OR_ID"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(notificationChannelId, ctx.resources.getString(R.string.alarm_body_message), NotificationManager.IMPORTANCE_HIGH)
notificationChannel.description = ctx.resources.getString(R.string.alarm_description)
notificationManager.createNotificationChannel(notificationChannel)
}
val notificationBuilder = NotificationCompat.Builder(ctx, notificationChannelId)
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.NOTIFICATION_ICON)
.setPriority(Notification.PRIORITY_MAX)
.setContentTitle(ctx.resources.getString(R.string.alarm_title))
.setContentText(ctx.resources.getString(R.string.alarm_body_message))
.setContentInfo(ctx.resources.getString(R.string.alarm_button_text))
val notificationIntent = Intent(ctx, NotificationActivity::class.java)
val pendingIntent = PendingIntent.getActivity(ctx, ALARM_SN, notificationIntent, 0)
notificationBuilder.addAction(android.R.drawable.btn_star, ctx.resources.getString(R.string.alarm_button_text), pendingIntent)
notificationBuilder.setContentIntent(pendingIntent)
notificationManager.notify(ALARM_SN, notificationBuilder.build())
}
companion object {
const val ALARM_SN = 007
}
}
you might also need to have an activity to receive the notification's action:
class NotificationActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AlarmReceiver.clearNotification(this)
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot) {
// Start the app before finishing
val startAppIntent = Intent(applicationContext, ActivityToOpen::class.java)
startAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(startAppIntent)
}
finish()
}
Finally, your function to create the notification should have something like this:
fun notification(duration: Int) { // duration in ms
val sendNotificationIntent = Intent(this, AlarmReceiver::class.java)
val delayedIntent = PendingIntent.getBroadcast(this, ALARM_CODE, sendNotificationIntent, PendingIntent.FLAG_CANCEL_CURRENT)
val alarms = this.applicationContext.getSystemService(ALARM_SERVICE) as AlarmManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarms.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + duration, delayedIntent)
} else {
alarms.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + duration, delayedIntent)
}
}
I am trying to make a bottom sheet; the code seems correct but I am having issues with the build.gradle. I am having trouble when I try to add in implementation "com.google.android.material:material:$material_version". I receive the error
"Could not get unknown property 'material_version' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler."
Any assistance would be appreciated
build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.bottom_sheet"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "com.google.android.material:material:$material_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
BottomSheetActivity.kt
class BottomSheetActivity : AppCompatActivity() {
private lateinit var standardBottomSheetBehavior: BottomSheetBehavior<View>
private val startColor = Color.parseColor("#00FFFFFF")
private val endColor = Color.parseColor("#FFFFFFFF")
private val textColor = Color.parseColor("#FF000000")
private var modalDismissWithAnimation = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bottom_sheet)
setupButtons()
setupStandardBottomSheet()
//animateStandardBottomSheetStates()
}
private fun setupButtons() {
standardBottomSheetButton.setOnClickListener {
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
private fun setupStandardBottomSheet() {
standardBottomSheetBehavior = BottomSheetBehavior.from(standardBottomSheet)
val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
textView.text = when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> "STATE_EXPANDED"
BottomSheetBehavior.STATE_COLLAPSED -> "STATE_COLLAPSED"
BottomSheetBehavior.STATE_DRAGGING -> "STATE_DRAGGING"
BottomSheetBehavior.STATE_HALF_EXPANDED -> "STATE_HALF_EXPANDED"
BottomSheetBehavior.STATE_HIDDEN -> "STATE_HIDDEN"
BottomSheetBehavior.STATE_SETTLING -> "STATE_SETTLING"
else -> null
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val fraction = (slideOffset + 1f) / 2f
val color = ArgbEvaluatorCompat.getInstance().evaluate(fraction, startColor, endColor)
slideView.setBackgroundColor(color)
}
}
standardBottomSheetBehavior.addBottomSheetCallback(bottomSheetCallback)
standardBottomSheetBehavior.saveFlags = BottomSheetBehavior.SAVE_ALL
textView.setTextColor(textColor)
}
private fun showModalBottomSheet() {
val modalBottomSheet = ModalBottomSheet.newInstance(modalDismissWithAnimation)
modalBottomSheet.show(supportFragmentManager, ModalBottomSheet.TAG)
}
private fun animateStandardBottomSheetStates() {
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}, 1000L)
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}, 2000L)
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
}, 3000L)
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
}, 4000L)
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}, 5000L)
}
}
ModalBottomSheet.kt
class ModalBottomSheet : BottomSheetDialogFragment() {
private var dismissWithAnimation = false
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.modal_bottom_sheet, container, false)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
dismissWithAnimation = arguments?.getBoolean(ARG_DISMISS_WITH_ANIMATION) ?: false
(requireDialog() as BottomSheetDialog).dismissWithAnimation = dismissWithAnimation
}
companion object {
const val TAG = "ModalBottomSheet"
private const val ARG_DISMISS_WITH_ANIMATION = "dismiss_with_animation"
fun newInstance(dismissWithAnimation: Boolean): ModalBottomSheet {
val modalBottomSheet = ModalBottomSheet()
modalBottomSheet.arguments = bundleOf(ARG_DISMISS_WITH_ANIMATION to dismissWithAnimation)
return modalBottomSheet
}
}
}
You need to change this line:
implementation "com.google.android.material:material:$material_version"
to this:
implementation 'com.google.android.material:material:1.2.0-alpha03'
or add $material_version parameter to your build.gradle file