Click listener for entire Snakbar layout - kotlin

I have a snackbar and I showing information to users. If user click Snackbar, I want to open an other fragment.
private fun showLastUnsuccessfulLoginMessage(message: String) {
val snackbar =
Snackbar.make(view!!, message , Snackbar.LENGTH_INDEFINITE)
snackbar.view.setSafeOnClickListener {
Log.wtf("clicked","setSafeOnClickListenerClicked")
}
snackbar.view.z=200f
snackbar.view.translationZ=200f
snackbar.view.setBackgroundColor(ContextCompat.getColor(activity!!,R.color.colorWhite))
val snackbarTextView: TextView = snackbar.view.findViewById(R.id.snackbar_text)
snackbarTextView.setTextColor(ContextCompat.getColor(activity!!,R.color.colorBlack))
snackbarTextView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_warning_red, 0, 0, 0)
snackbarTextView.compoundDrawablePadding = resources.getDimensionPixelOffset(R.dimen.space_s)
val params =
snackbar.view.layoutParams
(params as FrameLayout.LayoutParams).gravity = Gravity.TOP
snackbar.view.layoutParams = params
snackbar.view.visibility = View.INVISIBLE
snackbar.addCallback(object : Snackbar.Callback() {
override fun onShown(snackbar: Snackbar?) {
super.onShown(snackbar)
animateViewFromTop(snackbar!!.view)
}
})
snackbar.show()
isShowedUnsuccessfulLoginMessage = true
object : CountDownTimer(8000, 1000) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
animateViewToTop(snackbar.view)
}
}.start()
}
With this code, Snackbar is showing and when I click the snackbar, nothing happened.
snackbar.view.setSafeOnClickListener {
Log.wtf("clicked","setSafeOnClickListenerClicked")
}
This is not working fine.

Related

Kotlin: Edit icon dashboard of icons between fragments

I'm trying to figure out the most efficient way to structure this problem..
I'd like to click on the 'EDIT' icon in the dashboard of the MainFragment, display a DialogFragment, allow user to select/deselect up to 5 icons, save the selection, close the DialogFragment, and update the MainFragment.
Should I use MutableLiveData/Observer from a ViewModel? Or is there a better approach? I currently cannot figure out how to use the ViewModel approach correctly...
So far, this is the code I have:
MainFragment: https://i.stack.imgur.com/5fRt2.png
DialogFragment: https://i.stack.imgur.com/ZvW3d.png
ViewModel Class:
class IconDashboardViewModel() : ViewModel(){
var liveDataDashIcons: MutableLiveData<MutableList<String>> = MutableLiveData()
var liveItemData: MutableLiveData<String> = MutableLiveData()
// Observer for live list
fun getLiveDataObserver(): MutableLiveData<MutableList<String>> {
return liveDataDashIcons
}
// Observer for each icon
fun getLiveItemObserver(): MutableLiveData<String> {
return liveItemData
}
// Set icon list
fun setLiveDashIconsList(iconList: MutableLiveData<MutableList<String>>) {
liveDataDashIcons.value = iconList.value
}
// Set data for data
fun setItemData(icon : MutableLiveData<String>) {
liveItemData.value = icon.toString()
}
var iconList = mutableListOf<String>()
}
MainFragment:
private fun populateIconList() : MutableLiveData<MutableList> {
var iconList = viewModel.liveDataDashIcons
// Roster icon
if (roster_dash_layout.visibility == View.VISIBLE) {
iconList.value!!.add(getString(R.string.roster))
} else {
if (iconList.value!!.contains(getString(R.string.roster))) {
iconList.value!!.remove(getString(R.string.roster))
}
}
}
DialogFragment:
private fun setIconList(iconList: MutableList){
var iconList = viewModel.iconList
Log.d(TAG, "viewModel iconList = " + iconList)
if (iconList.contains(getString(R.string.roster))) {
binding.radioButtonRosterPick.setBackgroundResource(R.drawable.icon_helmet_blue_bg)
}
}

Android Bottom Sheet is not working in Fragment

I have added the bottom sheet dialog on a fragment.
Right now I can't open it.
Whenever I click on the show button it doesn't work at all.
How can I fix this problem?
CreateFragment.kt
class CreateFragment : Fragment() {
lateinit var binding: FragmentCreateBinding;
val viewModel: NotesViewModel by viewModels()
private var color = -1
private val currentDate = SimpleDateFormat.getInstance().format(Date())
private lateinit var result: String
private val job = CoroutineScope(Dispatchers.Main)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentCreateBinding.inflate(layoutInflater, container, false)
val animation = MaterialContainerTransform().apply {
drawingViewId = R.id.createFragment
scrimColor = Color.TRANSPARENT
duration = 300L
}
binding.backbutton.setOnClickListener {
requireView().hideKeyboard()
Navigation.findNavController(it).popBackStack()
}
sharedElementEnterTransition = animation
sharedElementReturnTransition = animation
binding.fabcolorpick.setOnClickListener {
val bottomSheetDialog = BottomSheetDialog(
requireContext(),
R.style.BottomSheetDialogTheme
)
val bottomSheetView: View = layoutInflater.inflate(
R.layout.bottomsheetlayout,
null,
)
val bottomSheetBinding = BottomsheetlayoutBinding.bind(bottomSheetView)
bottomSheetBinding.apply {
colorpicker.apply {
setSelectedColor(color)
setOnColorSelectedListener { value ->
color = value
binding.apply {
createFragmentxmlid.setBackgroundColor(color)
toolbarfragmentnotecontent.setBackgroundColor(color)
bottombar.setBackgroundColor(color)
activity?.window?.statusBarColor = color
}
bottomSheetBinding.bottomSheetparent.setCardBackgroundColor(color)
}
}
bottomSheetparent.setCardBackgroundColor(color)
}
bottomSheetView.post {
bottomSheetDialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
}
binding.btndonenotes.setOnClickListener {
createNotes(it)
}
try {
binding.edittextnote.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
binding.bottombar.visibility = View.VISIBLE
binding.edittextnote.setStylesBar(binding.styleBar)
} else {
binding.bottombar.visibility = View.GONE
}
}
} catch (e: Throwable) {
Log.d("TAG", e.stackTraceToString())
}
return binding.root
}
this is how I would do it
create the view
set view as content of dialog
call the dialog's show() method to show it or dismiss() method to dismiss it
// the content view
val bottomSheetView: View = layoutInflater.inflate(
R.layout.bottomsheetlayout,
null,
)
// and the dialog
val bottomSheetDialog = BottomSheetDialog( requireContext(),R.style.BottomSheetDialogTheme).apply{
setContent(bottomSheetView)
// or if I am using viewBinding
setContent(bottomSheetBinding.root)
}
// then in button's onClick
button.setOnClickListener{
bottomSheetDialog.show()
}

How to show user dialog box after recyclerview item click

I have an image button in my recylerview and when users click it, I want a dialog box to pop up and allow the user to edit the data in the reyclerview and save the changes.
My Adapter code
class Adapter(private var records: ArrayList<AudioRecord>, var listener: OnItemClickListener) : RecyclerView.Adapter<Adapter.ViewHolder>() {
private var editMode = false
fun isEditMode() :Boolean{return editMode}
#SuppressLint("NotifyDataSetChanged")
fun setEditMode(mode: Boolean){
if(editMode != mode){
editMode = mode
notifyDataSetChanged()
}
}
inner class ViewHolder(val binding: ItemviewLayoutBinding): RecyclerView.ViewHolder(binding.root ), View.OnClickListener, View.OnLongClickListener{
private var tvFileName : TextView = itemView.findViewById(R.id.tvFilename)
private var tvMeta : TextView = itemView.findViewById(R.id.tvMeta)
var checkbox : CheckBox = itemView.findViewById(R.id.checkBox)
val editBtn: ImageButton = itemView.findViewById(R.id.btnEdit)
init {
itemView.setOnClickListener(this)
itemView.setOnLongClickListener(this)
}
fun binding (audioRecord: AudioRecord) {
tvFileName.text = audioRecord.filename
tvMeta.text = audioRecord.duration
// checkbox.text = audioRecord.
}
override fun onClick(p0: View?) {
val position = adapterPosition
if(position != RecyclerView.NO_POSITION)
listener.onItemClickListener(position)
}
override fun onLongClick(p0: View?): Boolean {
val position = adapterPosition
if(position != RecyclerView.NO_POSITION)
listener.onItemLongClickListener(position)
return true
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(ItemviewLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
#SuppressLint("SetTextI18n", "SimpleDateFormat")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (position != RecyclerView.NO_POSITION){
val record: AudioRecord = records[position]
val sdf = SimpleDateFormat("dd/MM/yyyy")
val date = Date(record.timestamp)
val strDate = sdf.format(date)
holder.binding.tvFilename.text = record.filename
holder.binding.tvMeta.text = "${record.duration} $strDate"
if(editMode){
holder.checkbox.visibility = View.VISIBLE
holder.checkbox.isChecked = record.isChecked
holder.editBtn.visibility = View.GONE
}else{
holder.checkbox.visibility = View.GONE
holder.checkbox.isChecked = false
holder.editBtn.visibility = View.VISIBLE
}
holder.binding.btnEdit.setOnClickListener {
}
}
}
override fun getItemCount(): Int {
return records.size
}
}
Summary
When users click image button. Input dialog pops up
User must be able to edit data in recyclerview and save it.
change class like this inner class ViewHolder(val binding: ItemviewLayoutBinding), var imageListener:(position:Int)->Unit)
where you call adapter , use imageListener function. Whatever you want to do you can do it inside this function. Then call it in your adapter.
in init
editBtn.setOnClickListener {
imageListener(adapterPosition)
}

Change API param based on Dialog Fragment input with MVVM in Kotlin

i'm a beginner in android & kotlin and i'm having an issue i been trying to figure out all day...
I have an app that fetches data from NewsApi and displays it in a recycler view , i am using Retrofit library and Room (to save favorite articles) with MVVM architecture. I want to add an option so that the user can select the country of the news from a dialog that pops up by clicking on a icon on the toolbar menu.
I have created a custom DialogFragment and have it show up, the dialog contains a spinner with a list of countries and i'm using FragmentResult and FragmentResultListener to pass the country value between dialog fragment and news fragment.
DialogFragment
class CountrySelectDialog : DialogFragment(R.layout.country_selection_dialog) {
private lateinit var binding: CountrySelectionDialogBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = CountrySelectionDialogBinding.bind(view)
binding.spCountrySelection.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
adapterView: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
Toast.makeText(
context,
"you selected ${adapterView?.getItemAtPosition(position).toString()}",
Toast.LENGTH_SHORT
).show()
}
override fun onNothingSelected(adapterView: AdapterView<*>?) {
}
}
binding.btnCancel.setOnClickListener {
this.dismiss()
}
binding.btnConfirm.setOnClickListener {
val result = binding.spCountrySelection.selectedItem.toString()
setFragmentResult("countryCode", bundleOf("bundleKey" to result))
this.dismiss()
}
}
}
The news Fragment is observing data from the View Model
class BreakingNewsFragment : Fragment(R.layout.fragment_breaking_news) {
lateinit var viewModel: NewsViewModel
lateinit var newsAdapter: NewsAdapter
private lateinit var binding: FragmentBreakingNewsBinding
val TAG = "BreakingNewsFragment"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentBreakingNewsBinding.bind(view)
viewModel = (activity as NewsActivity).viewModel
setUpRecyclerView()
setFragmentResultListener("countryCode") { countryCode, bundle ->
val result = bundle.getString("countryCode")
viewModel.countryCode = result!!}
viewModel.breakingNews.observe(viewLifecycleOwner, Observer {
when (it) {
is Resource.Success -> {
hideProgressBar()
it.data?.let {
newsAdapter.differ.submitList(it.articles.toList())
val totalPages = it.totalResults / QUERY_PAGE_SIZE + 2
isLastPage = viewModel.breakingNewsPage == totalPages
}
}
is Resource.Error -> {
hideProgressBar()
it.message?.let {
Log.e(TAG, "An error occurred: $it")
}
}
is Resource.Loading -> {
showProgressBar()
}
}
})
newsAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("article", it)
}
findNavController().navigate(
R.id.action_breakingNewsFragment_to_articleFragment, bundle
)
}
}
ViewModel:
class NewsViewModel(val newsRepository: NewsRepository, val app: Application) : AndroidViewModel(app) {
val breakingNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()
var breakingNewsPage = 1
var breakingNewsResponse: NewsResponse? = null
val searchNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()
var searchNewsPage = 1
var searchNewsResponse: NewsResponse? = null
var countryCode :String = "it"
init {
getBreakingNews(countryCode)
}
fun getBreakingNews(countryCode: String) {
viewModelScope.launch {
breakingNews.postValue(Resource.Loading())
val response = newsRepository.getBreakingNews(countryCode, breakingNewsPage)
breakingNews.postValue(handleBreakingNewsResponse(response))
}
}
fun handleBreakingNewsResponse(response: Response<NewsResponse>): Resource<NewsResponse> {
if (response.isSuccessful) {
response.body()?.let { resultResponse ->
breakingNewsPage++
if (breakingNewsResponse == null) {
breakingNewsResponse = resultResponse
} else {
val oldArticles = breakingNewsResponse?.articles
val newArticles = resultResponse.articles
oldArticles?.addAll(newArticles)
}
return Resource.Success(breakingNewsResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}
fun searchNews(searchQuery: String) {
viewModelScope.launch {
searchNews.postValue(Resource.Loading())
val response = newsRepository.searchNews(searchQuery, searchNewsPage)
searchNews.postValue((handleSearchNewsResponse(response)))
}
}
fun handleSearchNewsResponse(response: Response<NewsResponse>): Resource<NewsResponse> {
if (response.isSuccessful) {
response.body()?.let { resultResponse ->
searchNewsPage++
if (searchNewsResponse == null) {
searchNewsResponse = resultResponse
} else {
val oldArticles = searchNewsResponse?.articles
val newArticles = resultResponse.articles
oldArticles?.addAll(newArticles)
}
return Resource.Success(searchNewsResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}
}
When i click on the icon on the toolbar menu the dialog appears and works fine but i can't seem to find a way to have the recycler view update with new data using given value for country
I searched everywhere and couldn't find a solution (or probably didn't understand it :S) can someone guide me into the right direction? I'm so lost...
When I click on the icon on the toolbar menu the dialog appears and works fine but I can't seem to find a way to have the recycler view update with new data using given value for country.

how to save and retrieve application info to shared preference in kotlin?

I want to hide app icon from grid view and save it.
I can save application info to shared preferences as mutable set string and get it but cant convert string to application info and show in my grid view
my app activity
private var applist: List<ApplicationInfo>? = null
private var listadaptor: ApplicationAdapter? = null
private var grid: GridView? = null
private var mSelected: ArrayList<Any> = ArrayList()
var context: Activity = this
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_apps)
val packageManager = getPackageManager()
LoadApplications().execute()
grid = findViewById<View>(R.id.grid) as GridView
grid!!.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE)
grid!!.adapter = listadaptor
grid!!.onItemClickListener = AdapterView.OnItemClickListener { parent: AdapterView<*>?, view: View?, position: Int, id: Long ->
val app = applist!![position]
try {
val intent = packageManager.getLaunchIntentForPackage(app.packageName)
intent?.let { startActivity(it) }
} catch (e: Exception) {
Toast.makeText(this#appsActivity, e.message, Toast.LENGTH_LONG).show()
}
}
grid!!.onItemLongClickListener = AdapterView.OnItemLongClickListener { parent, view, position, id ->
val position1: String = (position).toString()
if (mSelected.contains(position1)) {
mSelected.remove(position1)
view.setBackgroundColor(Color.TRANSPARENT) // remove item from list
// update view (v) state here
// eg: remove highlight
} else {
mSelected.add(position1)
view.setBackgroundColor(Color.LTGRAY) // add item to list
// update view (v) state here
// eg: add highlight
}
button3.setOnClickListener(
object : View.OnClickListener {
override fun onClick(view: View?) {
val builder1: AlertDialog.Builder = AlertDialog.Builder(this#appsActivity)
builder1.setMessage("Are you sure you want to delete it ?")
builder1.setCancelable(true)
builder1.setPositiveButton(
"Yes",
DialogInterface.OnClickListener { dialog, id ->
deleteSelectedItems()
mSelected.remove(position)
listadaptor!!.notifyDataSetChanged()
val app = applist!![position]
listadaptor!!.remove(app)
})
builder1.setNegativeButton(
"No",
DialogInterface.OnClickListener { dialog, id -> dialog.cancel() })
val alert11: AlertDialog = builder1.create()
alert11.show()
}
})
true
}
}
private fun deleteSelectedItems() {
val checked: SparseBooleanArray = grid!!.getCheckedItemPositions()
if (checked != null) {
val list: List<Any> = mSelected
for (i in 0 until checked.size()) {
if (checked.valueAt(i)) {
mSelected.remove(checked.keyAt(i))
}
}
}
}
private fun checkForLaunchIntent(list: List<ApplicationInfo>): List<ApplicationInfo> {
val applist = ArrayList<ApplicationInfo>()
for (info in list) {
try {
if (null != packageManager!!.getLaunchIntentForPackage(info.packageName)) {
applist.add(info)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
Collections.sort(applist, ApplicationInfo.DisplayNameComparator(packageManager))
return applist
}
#SuppressLint("StaticFieldLeak")
private inner class LoadApplications : AsyncTask<Void?, Void?, Void?>() {
override fun doInBackground(vararg params: Void?): Void? {
applist = checkForLaunchIntent(packageManager!!.getInstalledApplications(
PackageManager.GET_META_DATA))
listadaptor = ApplicationAdapter(this#appsActivity,
R.layout.grid_item, applist!!)
return null
}
override fun onPostExecute(result: Void?) {
grid!!.adapter = listadaptor
super.onPostExecute(result)
}
}
items are deleted, but after re-running the application, all installed apps will be restored in gridview
You can look into my open source project LibTron which has one module library for SharedPref written in Kotlin.
To use the library follow the instruction in Project ReadMe
Example to use the library:
val applicationInfo: ApplicationInfo = sharedprefrence.Object(name = "sharedprefKey", defaultValue = null)
Or in case you want to use it without the help of the you can use GSON, Moshi, Jackson type libraries to convert to/from string to your ApplicationInfo class while saving or reading from the Sharedprefrence