I am trying to build a simple app in Kotlin using MVVM architecture, and I'm struggling with switching fragments. I get it to "change" - on a button press it does nothing, and on a second press it crashes saying "Navigation action/destination MAIN_to_RESULT cannot be found from the current destination RESULT" - so it clearly changed the fragments from MAIN to RESULT, but I still see the MAIN fragment)
Here is my MAIN fragment:
class MainFragment : Fragment() {
private lateinit var viewModel: MainViewModel
lateinit var binding: FragmentMainBinding
companion object {
fun newInstance() = MainFragment()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = (activity as MainActivity).viewModel
binding.setVariable(myViewModel, viewModel)
viewModel.bnd = binding
binding.button2.setOnClickListener { viewModel.chng() }
binding.submitButton.setOnClickListener {
val controller = NavHostFragment.findNavController(this)
controller.navigate(R.id.action_mainFragment_to_resultFragment)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false)
binding.setLifecycleOwner(this)
return binding.root
}
}
OTHER fragment:
class ResultFragment : Fragment() {
private lateinit var viewModel: MainViewModel
lateinit var binding: FragmentMainBinding
companion object {
fun newInstance() = ResultFragment()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false)
binding.setLifecycleOwner(this)
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = (activity as MainActivity).viewModel
binding.setVariable(BR.myViewModel, viewModel)
binding.button2.setOnClickListener { viewModel.chng() }
viewModel.bnd = binding
}
}
MainViewModel:
class MainViewModel(application: Application) : AndroidViewModel(application) {
val rps = Repository()
lateinit var bnd : FragmentMainBinding
var changing = false
var SPEED_OF_CHANGING = 100L
var actualCountedCards = 0
var numberOfCardsToRotate = 0
var numberOfRotatedCards = 0
lateinit var actualCard : Card
var mainHandler: Handler = Handler(Looper.getMainLooper())
private val changeCard = object : Runnable {
override fun run() {
if (changing) {
actualCard = rps.Cards.random()
bnd.cardView.setImageResource(actualCard.image)
actualCountedCards += actualCard.power
numberOfRotatedCards += 1
Log.d("tagicek", "${numberOfRotatedCards}/${numberOfCardsToRotate}, ${actualCountedCards}")
if (numberOfRotatedCards >= numberOfCardsToRotate) {
chng()
bnd.editTextTextPersonName.visibility = View.VISIBLE
bnd.submitButton.visibility = View.VISIBLE
bnd.button2.visibility = View.INVISIBLE
}
mainHandler.postDelayed(this, SPEED_OF_CHANGING)
}
}
}
fun chng() {
if (changing == true) {
mainHandler.removeCallbacks(changeCard)
actualCountedCards = 0
numberOfRotatedCards = 0
bnd.cardView.setImageResource(R.drawable.bg)
changing = false
} else {
numberOfCardsToRotate = (1..51).random()
mainHandler.post(changeCard)
changing = true
}
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow()
}
}
}
I am pretty sure the problem is with my bindings and views, but I can't wrap my head around it. I have tried probably every positioning of defining the NavController and the different views passed into it, but it still doesn't work.
Related
***I am trying to create af spinningWheel animation with my imageView spinning once the button is pressed. I found a youtube video with some java code i converted into kotlin. With the code below nothing happens when the button is pushed. I have used the rotateAnimation class and some calculations in the GameViewModel thus far, and call the spin() in the GameFragment class' onCreateView().
The code below are the two classes i use for the rotateAnimation but it doesn't seem to work. I am not sure which part is the problem. Does anyone know?***
class GameViewModel : ViewModel() {
private val fields = arrayOf("1","2","3","4","5","6","7")
private val fieldDegrees = IntArray(fields.size)
private var degree = 0
var isSpinning = false
fun getDegreesForSectors(){
val oneFieldsDegrees = 360/fields.size
for (i in fields.indices){
fieldDegrees[i] = (i+1) * oneFieldsDegrees
}
}
fun spin(imageView: ImageView){
isSpinning = true
degree = (0..fields.size).random()
val rotateAnimation = RotateAnimation(0.toFloat(),
(360 * fields.size + fieldDegrees[degree]).toFloat(),
RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f)
rotateAnimation.setDuration(3600)
rotateAnimation.setFillAfter(true)
rotateAnimation.setInterpolator(DecelerateInterpolator())
rotateAnimation.setAnimationListener(object : Animation.AnimationListener{
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
isSpinning = false
}
override fun onAnimationRepeat(animation: Animation) {}
})
imageView.startAnimation(rotateAnimation)
}
}
class GameFragment : Fragment() {
private lateinit var gameViewModel: GameViewModel
private var _binding: GameFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
gameViewModel =
ViewModelProvider(this).get(GameViewModel::class.java)
val spinBtn: Button? = view?.findViewById(R.id.spinBtn)
val wheelImage: ImageView? = view?.findViewById(R.id.Spinning_Wheel)
gameViewModel.getDegreesForSectors()
spinBtn?.setOnClickListener() {
if (!gameViewModel.isSpinning) {
gameViewModel.spin(wheelImage!!)
}
}
_binding = GameFragmentBinding.inflate(inflater, container, false)
val root: View = binding.root
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
You are accessing fragment view inside onCreateView(). This will return null since nothing has been inflated yet.
Use the binding variable to access the views.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
gameViewModel = ViewModelProvider(this).get(GameViewModel::class.java)
_binding = GameFragmentBinding.inflate(inflater, container, false)
gameViewModel.getDegreesForSectors()
binding.spinBtn.setOnClickListener() {
if (!gameViewModel.isSpinning) {
gameViewModel.spin(binding.spinningWheel)
}
}
return binding.root
}
I am making a simple application. There are 2 screens in the application: List screen, Add screen.
Scenario: When the application is opened, there is a list page on the screen. The user goes to the Adding page with the help of the Floating Action Button on the list page. Here, he enters the items with the help of Edit Text and comes to the List page by pressing the Add Button.
I am using MVVM in this application and I am a beginner. So I can't find the problem. Here is the problem: I am adding new elements to my list in the Add Fragment, but these elements are not seems in the List Fragment.
Thanks in advance.
Model Class
data class Movie(
val movieName: String,
val releaseDate: String
)
ViewModel class
class MovieViewModel : ViewModel() {
val movies = MutableLiveData<ArrayList<Movie>>()
var movieList = arrayListOf<Movie>()
fun addMovie(movie: Movie) {
movieList.add(movie)
movies.value = movieList
}
}
Adapter Class
class MovieAdapter : RecyclerView.Adapter<MovieAdapter.MyViewHolder>() {
private var movieList = emptyList<Movie>()
class MyViewHolder(private val binding: RowItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(movie: Movie) {
binding.textViewMovieName.text = movie.movieName
binding.textViewReleaseDate.text = movie.releaseDate
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = RowItemBinding.inflate(layoutInflater, parent, false)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = movieList[position]
holder.bind(currentItem)
}
override fun getItemCount(): Int {
return movieList.size
}
fun setData(movie: List<Movie>) {
val movieDiffUtil = MovieDiffUtil(movieList, movie)
val movieDiffResult = DiffUtil.calculateDiff(movieDiffUtil)
this.movieList = movie
movieDiffResult.dispatchUpdatesTo(this)
}
}
Add Fragment
class AddFragment : Fragment() {
private var _binding: FragmentAddBinding? = null
private val binding get() = _binding!!
private val movieViewModel: MovieViewModel by viewModels<MovieViewModel>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentAddBinding.inflate(inflater, container, false)
binding.buttonAdd.setOnClickListener {
insertData()
}
return binding.root
}
private fun insertData() {
val movieName = binding.editTextMovieName.text.toString()
val releaseDate = binding.editTextReleaseDate.text.toString()
val movie = Movie(movieName, releaseDate)
movieViewModel.addMovie(movie)
findNavController().navigate(R.id.action_addFragment_to_listFragment)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
List Fragment
class ListFragment : Fragment() {
private var _binding: FragmentListBinding? = null
private val binding get() = _binding!!
private val adapter: MovieAdapter by lazy { MovieAdapter() }
private val movieViewModel: MovieViewModel by viewModels<MovieViewModel>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentListBinding.inflate(inflater, container, false)
setAdapter()
movieViewModel.movies.observe(viewLifecycleOwner, { data ->
adapter.setData(data)
binding.textView.setText(data.get(0).movieName)
})
binding.floatingActionButton.setOnClickListener {
findNavController().navigate(R.id.action_listFragment_to_addFragment)
}
return binding.root
}
private fun setAdapter() {
val recyclerView = binding.recyclerView
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(requireActivity())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
After adding an item to a List<> you need to notify the Adapter that the data has changed.
You can do so by calling adapter.notifyDataSetChanged().
I added my List directly into the Adapter but you can create a function like in the following stackoverflow post.
How to update my Recyclerview using kotlin android?
So I've been wrestling with this for days and I need some help. I've made this code work in an activity, but then I move it to a fragment it doesn't work. Everything else is the same between the two.
Using the debugger with the working Activity, the line
apiService = retrofit.create<HomeJsonApiService>(HomeJsonApiService::class.java)
goes to getItemCount(). However in the fragment it goes directly to onCreateView in the Fragment. I've attached my code below. Thanks in advance for the help! And be gentle. I'm still new to this :)
First is my fragment:
class TabHomeActivity : Fragment() {
val itemList = ArrayList<HomeCards>()
lateinit var adapter: HomeCardsAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var binding = FragmentTabHomeActivityBinding.inflate(layoutInflater)
adapter = HomeCardsAdapter()
var rv = binding.rvHomeCards
rv.adapter = adapter
loadData()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.cards_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
private fun loadData() {
ApiManager.getInstance().service.listHeroes()
.enqueue(object : Callback<ResponseData<List<HomeCards>>> {
override fun onResponse(
call: Call<ResponseData<List<HomeCards>>>,
response: Response<ResponseData<List<HomeCards>>>
) {
val listData: List<HomeCards> = response.body()!!.data
// updating data from network to adapter
itemList.clear()
itemList.addAll(listData)
adapter.updateData(itemList)
adapter.notifyDataSetChanged()
}
override fun onFailure(call: Call<ResponseData<List<HomeCards>>>, t: Throwable) {
}
})
}
}
The HTTP request:
data class ResponseData<T> (
val code: Int,
val data: T
)
interface HomeJsonApiService {
#GET("marvel-heroes.asp?h=2")
fun listHeroes(): retrofit2.Call<ResponseData<List<HomeCards>>>
}
class ApiManager {
private var apiService: HomeJsonApiService? = null
init {
createService()
}
val service: HomeJsonApiService get() = apiService!!
private fun createService() {
val loggingInterceptor =
HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
override fun log(message: String) {
Log.i("Retrofit", message)
}
})
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.addInterceptor(loggingInterceptor)
.build()
val retrofit: Retrofit = Retrofit.Builder()
.client(client)
.baseUrl("https://www.mywebsite.com/jsonfolder/JSON/")
.addConverterFactory(GsonConverterFactory.create())
.build()
apiService = retrofit.create(HomeJsonApiService::class.java)
}
companion object {
private var instance: ApiManager? = null
fun getInstance(): ApiManager {
return instance ?: synchronized(this) {
ApiManager().also { instance = it }
}
}
}
}
And my adapter:
class HomeCardsAdapter() : RecyclerView.Adapter<HomeCardsAdapter.ViewHolder>() {
private lateinit var itemList: List<HomeCards>
lateinit var context: Context
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
context = parent.context
val view = LayoutInflater.from(context).inflate(R.layout.cards_home, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return if (::itemList.isInitialized) itemList.size else 0
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind()
}
fun updateData(list: List<HomeCards>) {
itemList = list;
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
//var binding = ActivityMainBinding(layoutInflater(inf))
fun bind() {
val item = itemList.get(adapterPosition)
ViewHolder(itemView).itemView.findViewById<TextView>(R.id.cardHomeTitle).text = item.name
ViewHolder(itemView).itemView.findViewById<TextView>(R.id.cardHomeTitle).text = item.superheroName
Glide.with(context)
.load(item.photo)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.circleCrop()
.into(ViewHolder(itemView).itemView.findViewById<ImageView>(R.id.cardHomeIcon))
}
}
}
class HomeCards {
#SerializedName("superhero_name")
var superheroName: String = ""
var name: String = ""
var photo: String = ""
}
The main problem is:
var binding = FragmentTabHomeActivityBinding.inflate(layoutInflater)
That is inside on onCreate but onCreateView is returning another view inflater.inflate(R.layout.cards_home, container, false)
So you are applying the adapter to a recycler that is on the binding, but the view on the screen is inflated from the layout. Change it to this:
private lateinit var binding: FragmentTabHomeActivityBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
binding = FragmentTabHomeActivityBinding.inflate(layoutInflater, container, false)
return binding.root
}
And move the code from from onCreate to onViewCreated but make sure to use the lateinit binding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = HomeCardsAdapter()
var rv = binding.rvHomeCards
rv.adapter = adapter
loadData()
}
After that there is a problem in your adapter: private lateinit var itemList: List<HomeCards> very specifically List<HomeCards>. The method notifyDataSetChanged doesn't work by changing or updating the reference of the data structure but when the collection is modified. Change it to this:
private val list = mutableListOf<HomeCards>()
override fun getItemCount(): Int {
return list.size()
}
fun updateData(list: List<HomeCards>) {
this.itemList.clear()
this.itemList.addAll(list)
notifyDataSetChanged()
}
If onResponse() gets called and provides response, verify that code updating UI is running on main/ui thread. Common source of issue when working with network (other threads).
activity?.runOnUiThread {
itemList.clear()
itemList.addAll(listData)
adapter.updateData(itemList)
adapter.notifyDataSetChanged()
}
I have an activity that contains 2 tabs and each tab has a fragment inside ViewPager. Each fragment have a RecyclerView.
When I navigate to another activity the data inside the Fragments should be updated. Although the data is being sent correctly to the fragment, the original data is displayed.
I tried using notifyDataSetChanged() method inside the fragment but it didn't work.
I also tried calling it from the activity like:
if (!pickedItemsList.isNullOrEmpty() && notScannedItemsFragment != null && notScannedItemsFragment.isAdded)
{
notScannedItemsFragment.notScannedItemsAdapter.notifyDataSetChanged()
}
However, it didn't work too.
That's how I am initiating the fragment:
override fun initFragments(savedInstanceState: Bundle?, pickedItemsList: ArrayList<OrderDetail>, remainigItemsList: ArrayList<OrderDetail>) {
val listener: ItemsInteractionListener = object : ItemsInteractionListener {
override fun onSwipeToRefresh() {
presenter.onSwipeToRefresh()
}
}
if (!pickedItemsList.isNullOrEmpty() && notScannedItemsFragment != null && notScannedItemsFragment.isAdded) {
notScannedItemsFragment.notScannedItemsAdapter.notifyDataSetChanged()
scannedItemsFragment = ScannedItemsFragment().newInstance(remainingItemsList)
notScannedItemsFragment = NotScannedItemsFragment().newInstance(pickedItemsList)!!
} else {
scannedItemsFragment = ScannedItemsFragment().newInstance(arrayListOf())
notScannedItemsFragment = NotScannedItemsFragment().newInstance(allItemsList)!!
}
scannedItemsFragment.setListener(listener)
notScannedItemsFragment.setListener(listener)
}
allItemList is the original list and pickedItemsList and remainingItemsList are the lists after the changes (that I got from the other activity)
This is one of the fragments classes:
class NotScannedItemsFragment : BaseFragment() {
private var listener: ItemsInteractionListener? = null
lateinit var notScannedItemsAdapter: OrderItemListingAdapter
private var itemRemainingCount: Int = 0
lateinit var notScannedItems: ArrayList<OrderDetail>
lateinit var recyclerView: RecyclerView
lateinit var fragmentView: View
fun newInstance(notScannedItems: ArrayList<OrderDetail>): NotScannedItemsFragment? {
val notScannedItemsFragment = NotScannedItemsFragment()
val args = Bundle()
val order = Gson().toJson(notScannedItems)
args.putString(IntentConstants.EXTRA_NOT_SCANNED_ITEM_LIST, order)
notScannedItemsFragment.setArguments(args)
return notScannedItemsFragment
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val str = arguments?.getString(IntentConstants.EXTRA_NOT_SCANNED_ITEM_LIST)
notScannedItems = Gson().fromJson(
str,
object : TypeToken<List<OrderDetail?>?>() {}.type
) as ArrayList<OrderDetail>
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
fragmentView = inflater.inflate(R.layout.fragment_not_scanned_items, container, false)
recyclerView = fragmentView.notScannedItemListing
return fragmentView
}
fun setListener(listener: ItemsInteractionListener) {
this.listener = listener
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setUpRecycler(view)
super.onViewCreated(view, savedInstanceState)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
}
private fun setUpRecycler(view: View) {
imageLoader = ImageLoader(context)
notScannedItemsAdapter = OrderItemListingAdapter(
false,
imageLoader,
object : ImageClickListener {
override fun onImageClick(
itemName: String,
itemQuantity: Int,
url: String,
barcodes: List<String>?
) {
startImageFullViewActivity(itemName, itemQuantity, url, barcodes)
}
})
notScannedItemsAdapter.addItem(notScannedItems)
notScannedItemsAdapter.notifyDataSetChanged()
view.notScannedItemListing.apply {
view.notScannedItemListing.layoutManager = LinearLayoutManager(context)
view.notScannedItemListing.setHasFixedSize(true)
view.notScannedItemListing.isNestedScrollingEnabled = false
adapter = notScannedItemsAdapter
}
notScannedItemsAdapter.printList()
}
fun showOrderItemListing(notScannedItems: ArrayList<OrderDetail>) {
this.notScannedItems = notScannedItems
itemRemainingCount = notScannedItems.size
}
fun getItemsRemainingCount(): Int{
return notScannedItems.size
}
fun clearItems() {
notScannedItemsAdapter.clearItems()
}
fun updateAdapterContent(pickedItemsList: ArrayList<OrderDetail>) {
if(this::notScannedItemsAdapter.isInitialized ) {
notScannedItemsAdapter.clearItems()
notScannedItemsAdapter.addItem(notScannedItems)
notScannedItemsAdapter.notifyDataSetChanged()
}
}
}
It turns out since I'm getting the list from arguments it's not updating with the new list. As stated here: Anything initialized in onCreate() is preserved if the Fragment is paused and resumed.
So I added a boolean variable loadListFromArgs and I only loaded the list from args if it's true and when I call updateAdapterContent I set it to false.
I am still doing my first steps with app development, so i would appreciate any kind of feedback for my code.
To my problem. I got two Fragments, "ListFragment.kt" and "SetListFilters.kt". My intention is to create a cursor instance in SetListFilters and then when I press a "apply"-button i perform a popBackStack while sending the cursor instance to ListFrament. To my understanding ListFragment will call OnCreateView() and there i want to pass the new cursor to my adapter so that the Recyclerview get filtered. I tried so many things but nothing worked for me. I hope you can help me. Here is my Code:
class SetListFilters(var transactionDB: SQLiteDatabase, var adapter: TransactionAdapter):Fragment(R.layout.fragment_set_list_filters), DataPassListener {
private lateinit var gridView : GridView
private lateinit var btnYearFilter : Button
private lateinit var btnMonthFilter : Button
private lateinit var btnWeekFilter : Button
private lateinit var btnRevenueFilter : Button
private lateinit var btnExpeneseFilter : Button
private lateinit var btnNeutralFilter : Button
private lateinit var btnSbmtFilter : Button
private lateinit var tvShowAmountFilter : TextView
private lateinit var sbAmountFilters : SeekBar
private val viewModel: ListViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_set_list_filters, container, false)
setUpViews(view)
setUpButtonOnclick()
setUpSeekbar()
val arrayAdapter: ArrayAdapter<CategoryEnum> = ArrayAdapter<CategoryEnum>(activity!!, android.R.layout.simple_list_item_multiple_choice, CategoryEnum.values())
gridView.setAdapter(arrayAdapter)
// When the user clicks on the GridItem
/*gridView.setOnItemClickListener(OnItemClickListener { a, v, position, id ->
val o: Any = gridView.getItemAtPosition(position)
})*/
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.filters.observe(viewLifecycleOwner, Observer { set ->
// Update the selected filters UI
}
}
fun onFilterSelected(filter: Filter) = viewModel.addFilter(filter)
fun onFilterDeselected(filter: Filter) = viewModel.removeFilter(filter)
private fun upDateQueryForDB(){
}
private fun getAllItemsNeu(): Cursor {
val selArgs = arrayOf("r")
return transactionDB!!.query(
TransactionList.TransactionEntry.TABLE_NAME,
null,
"type = ?",
selArgs,
null,
null,
TransactionList.TransactionEntry.COLUMN_CREATEDAT + " DESC")
}
private fun setUpViews(view: View){
gridView = view.findViewById(R.id.gvCategoryFilter )
btnExpeneseFilter = view.findViewById(R.id.btnExpenseFilter)
btnMonthFilter = view.findViewById(R.id.btnMonthFilter)
btnWeekFilter = view.findViewById(R.id.btnWeekFilter)
btnNeutralFilter = view.findViewById(R.id.btnNeutralFilter)
btnRevenueFilter = view.findViewById(R.id.btnRevenueFilter)
btnSbmtFilter = view.findViewById(R.id.btnSbmtFilter)
btnYearFilter = view.findViewById(R.id.btnYearFilter)
sbAmountFilters = view.findViewById(R.id.seekBar)
tvShowAmountFilter = view.findViewById(R.id.tvFilterAmount)
}
private fun setUpButtonOnclick(){
btnExpeneseFilter.setOnClickListener { changeButtonAppearance(btnExpeneseFilter) }
btnMonthFilter.setOnClickListener { changeButtonAppearance(btnMonthFilter) }
btnWeekFilter.setOnClickListener { changeButtonAppearance(btnWeekFilter) }
btnNeutralFilter.setOnClickListener { changeButtonAppearance(btnNeutralFilter) }
btnRevenueFilter.setOnClickListener { changeButtonAppearance(btnRevenueFilter) }
btnYearFilter.setOnClickListener { changeButtonAppearance(btnYearFilter) }
btnSbmtFilter.setOnClickListener{
mainActivity.passDataCom(getAllItemsNeu())
activity!!.supportFragmentManager.popBackStack()
}
}
private fun changeButtonAppearance(button:Button) {
if(button.tag == "notPressed"){
button.setBackgroundResource(R.drawable.rounded_select_button_pressed)
button.setTextColor(Color.WHITE)
button.tag = "pressed"
}else{
button.setBackgroundResource(R.drawable.rounded_select_button)
button.setTextColor(ContextCompat.getColor(context!!,R.color.mainBlue))
button.tag ="notPressed"
}
}
private fun setUpSeekbar(){
sbAmountFilters.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
// Display the current progress of SeekBar
tvShowAmountFilter.text = "< $i"
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// Do something
//Toast.makeText(context!!,"start tracking",Toast.LENGTH_SHORT).show()
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// Do something
//Toast.makeText(context!!,"stop tracking",Toast.LENGTH_SHORT).show()
if(tvShowAmountFilter.text.toString()=="< 0"){
tvShowAmountFilter.text = "none"
}
}
})
}
override fun onAttach(context: Context) {
super.onAttach(context)
try{
mCallback = (OnImageClickListener) //folled the tutorial, dont know what to replace it with
}
}
}
class ListFragment:Fragment(R.layout.fragment_list) {
lateinit var transactionDB : SQLiteDatabase
lateinit var adapter : TransactionAdapter
private lateinit var filterBtn : ImageButton
private lateinit var flActBtn : FloatingActionButton
var mCursorFilter : Cursor? = null
private val viewModel: ListViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val dbHelper = TransactionDBHelper(activity)
transactionDB = dbHelper.writableDatabase
adapter = TransactionAdapter(activity!!, getAllItems())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.filteredList.observe(viewLifecycleOwner, Observer { list ->
//TODO
}
}
private fun addRandomTransactionItem() {
var a = 1234.56
for (i in 0..10) {
if(i%2==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('r', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else if(i%5==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('ne', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else if(i%6==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('ne', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else{
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('e', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}
}
}
private fun getAllItems(): Cursor {
return transactionDB!!.query(
TransactionList.TransactionEntry.TABLE_NAME,
null,
null,
null,
null,
null,
TransactionList.TransactionEntry.COLUMN_CREATEDAT + " DESC")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_list, container, false)
val rvRecyclerView = view.findViewById<RecyclerView>(R.id.rvRecyclerView)
rvRecyclerView.layoutManager = LinearLayoutManager(activity)
if(mCursorFilter!=null){
adapter.swapCursor(mCursorFilter!!)
}
rvRecyclerView.adapter = this.adapter
rvRecyclerView.addItemDecoration(MarginItemDecoration(10))
flActBtn = view.findViewById(R.id.floatingActionButton)
flActBtn.setOnClickListener {
var ft:FragmentTransaction = activity!!.supportFragmentManager.beginTransaction()
ft.replace(R.id.flFrameLayout, AddItemFragment(transactionDB, adapter))
ft.addToBackStack(null)
ft.commit()
}
filterBtn=view.findViewById(R.id.ibFilterBtn)
filterBtn.setOnClickListener {
var ft:FragmentTransaction = activity!!.supportFragmentManager.beginTransaction()
ft.replace(R.id.flFrameLayout, SetListFilters(transactionDB, adapter))
ft.addToBackStack(null)
ft.commit()
}
addRandomTransactionItem()
return view
}
}
class MainActivity() : AppCompatActivity() {
var mCursorFilters: Cursor? = null
private val viewModel: ItemViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.selectedItem.observe(this, Observer { item ->
// TODO
})
val homeFragment = HomeFragment()
val listFragment = ListFragment()
val profileFragment = ProfileFragment()
setCurrentFragment(homeFragment)
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
bottomNavigationView.setOnNavigationItemSelectedListener {
var ft: FragmentTransaction = this.supportFragmentManager.beginTransaction()
when (it.itemId) {
R.id.pageHome -> ft.replace(R.id.flFrameLayout, homeFragment) // setCurrentFragment(homeFragment)
R.id.pageList -> ft.replace(R.id.flFrameLayout, listFragment) //setCurrentFragment(listFragment)
R.id.pageProfile -> ft.replace(R.id.flFrameLayout, profileFragment) //setCurrentFragment(profileFragment)
}
// ft.replace(R.id.flFrameLayout, AddItemFragment())
ft.addToBackStack(null)
ft.commit()
true
}
}
private fun setCurrentFragment(fragment: Fragment){
supportFragmentManager.beginTransaction().apply {
replace(R.id.flFrameLayout, fragment)
commit()
}
}
}