From fe0d11b75598732a2b6efdd23cdd29ec967fc1c2 Mon Sep 17 00:00:00 2001 From: Conny Duck Date: Sun, 22 Dec 2019 11:42:13 +0100 Subject: [PATCH 01/10] convert ScheduledTootAdapter to Kotlin --- .../tusky/ScheduledTootActivity.kt | 3 +- .../tusky/adapter/ScheduledTootAdapter.java | 125 ------------------ .../tusky/adapter/ScheduledTootAdapter.kt | 87 ++++++++++++ 3 files changed, 89 insertions(+), 126 deletions(-) delete mode 100644 app/src/main/java/com/keylesspalace/tusky/adapter/ScheduledTootAdapter.java create mode 100644 app/src/main/java/com/keylesspalace/tusky/adapter/ScheduledTootAdapter.kt diff --git a/app/src/main/java/com/keylesspalace/tusky/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ScheduledTootActivity.kt index 5467a3b8..3399eea0 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ScheduledTootActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/ScheduledTootActivity.kt @@ -9,6 +9,7 @@ import androidx.appcompat.widget.Toolbar import androidx.lifecycle.Lifecycle import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager +import com.keylesspalace.tusky.adapter.ScheduledTootAction import com.keylesspalace.tusky.adapter.ScheduledTootAdapter import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.StatusScheduledEvent @@ -29,7 +30,7 @@ import retrofit2.Response import javax.inject.Inject -class ScheduledTootActivity : BaseActivity(), ScheduledTootAdapter.ScheduledTootAction, Injectable { +class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { companion object { @JvmStatic diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/ScheduledTootAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/ScheduledTootAdapter.java deleted file mode 100644 index 6698dd37..00000000 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/ScheduledTootAdapter.java +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright 2019 kyori19 - * - * This file is a part of Tusky. - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 3 of the - * License, or (at your option) any later version. - * - * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. - * - * You should have received a copy of the GNU General Public License along with Tusky; if not, - * see . */ - -package com.keylesspalace.tusky.adapter; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; - -import com.keylesspalace.tusky.R; -import com.keylesspalace.tusky.entity.ScheduledStatus; - -import java.util.ArrayList; -import java.util.List; - -public class ScheduledTootAdapter extends RecyclerView.Adapter { - private List list; - private ScheduledTootAction handler; - - public ScheduledTootAdapter(Context context) { - super(); - list = new ArrayList<>(); - handler = (ScheduledTootAction) context; - } - - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_scheduled_toot, parent, false); - return new TootViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { - TootViewHolder holder = (TootViewHolder) viewHolder; - holder.bind(getItem(position)); - } - - @Override - public int getItemCount() { - return list.size(); - } - - public void setItems(List newToot) { - list = new ArrayList<>(); - list.addAll(newToot); - } - - @Nullable - public ScheduledStatus removeItem(int position) { - if (position < 0 || position >= list.size()) { - return null; - } - ScheduledStatus toot = list.remove(position); - notifyItemRemoved(position); - return toot; - } - - private ScheduledStatus getItem(int position) { - if (position >= 0 && position < list.size()) { - return list.get(position); - } - return null; - } - - public interface ScheduledTootAction { - void edit(int position, ScheduledStatus item); - - void delete(int position, ScheduledStatus item); - } - - private class TootViewHolder extends RecyclerView.ViewHolder { - View view; - TextView text; - ImageButton edit; - ImageButton delete; - - TootViewHolder(View view) { - super(view); - this.view = view; - this.text = view.findViewById(R.id.text); - this.edit = view.findViewById(R.id.edit); - this.delete = view.findViewById(R.id.delete); - } - - void bind(final ScheduledStatus item) { - edit.setEnabled(true); - delete.setEnabled(true); - - if (item != null) { - text.setText(item.getParams().getText()); - - edit.setOnClickListener(v -> { - v.setEnabled(false); - handler.edit(getAdapterPosition(), item); - }); - - delete.setOnClickListener(v -> { - v.setEnabled(false); - handler.delete(getAdapterPosition(), item); - }); - } - } - } -} diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/ScheduledTootAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/ScheduledTootAdapter.kt new file mode 100644 index 00000000..85e81d00 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/ScheduledTootAdapter.kt @@ -0,0 +1,87 @@ +/* Copyright 2019 Tusky Contributors + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tusky; if not, + * see . */ + +package com.keylesspalace.tusky.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageButton +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.keylesspalace.tusky.R +import com.keylesspalace.tusky.entity.ScheduledStatus + +interface ScheduledTootAction { + fun edit(position: Int, item: ScheduledStatus?) + fun delete(position: Int, item: ScheduledStatus?) +} + +class ScheduledTootAdapter( + val listener: ScheduledTootAction +) : RecyclerView.Adapter() { + + private var items: MutableList = mutableListOf() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TootViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.item_scheduled_toot, parent, false) + return TootViewHolder(view) + } + + override fun onBindViewHolder(viewHolder: TootViewHolder, position: Int) { + viewHolder.bind(items[position]) + } + + override fun getItemCount() = items.size + + fun setItems(newItems: List) { + items = newItems.toMutableList() + notifyDataSetChanged() + } + + fun removeItem(position: Int): ScheduledStatus? { + if (position < 0 || position >= items.size) { + return null + } + val toot = items.removeAt(position) + notifyItemRemoved(position) + return toot + } + + inner class TootViewHolder(view: View) : RecyclerView.ViewHolder(view) { + + private val text: TextView = view.findViewById(R.id.text) + private val edit: ImageButton = view.findViewById(R.id.edit) + private val delete: ImageButton = view.findViewById(R.id.delete) + + fun bind(item: ScheduledStatus) { + edit.isEnabled = true + delete.isEnabled = true + text.text = item.params.text + edit.setOnClickListener { v: View -> + v.isEnabled = false + listener.edit(adapterPosition, item) + } + delete.setOnClickListener { v: View -> + v.isEnabled = false + listener.delete(adapterPosition, item) + } + + } + + } + +} \ No newline at end of file From 7f2aab7723fe6b9a2a776f2584ad6df2cd04f7c2 Mon Sep 17 00:00:00 2001 From: Conny Duck Date: Sun, 22 Dec 2019 11:47:34 +0100 Subject: [PATCH 02/10] move classes to component packages --- app/src/main/AndroidManifest.xml | 2 +- app/src/main/java/com/keylesspalace/tusky/MainActivity.java | 1 + .../{ => components/scheduled}/ScheduledTootActivity.kt | 6 +++--- .../scheduled}/ScheduledTootAdapter.kt | 2 +- .../java/com/keylesspalace/tusky/di/ActivitiesModule.kt | 1 + 5 files changed, 7 insertions(+), 5 deletions(-) rename app/src/main/java/com/keylesspalace/tusky/{ => components/scheduled}/ScheduledTootActivity.kt (97%) rename app/src/main/java/com/keylesspalace/tusky/{adapter => components/scheduled}/ScheduledTootAdapter.kt (98%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 028b7aa4..0f77db16 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -137,7 +137,7 @@ android:name=".components.report.ReportActivity" android:windowSoftInputMode="stateAlwaysHidden|adjustResize" /> - + . */ -package com.keylesspalace.tusky.adapter +package com.keylesspalace.tusky.components.scheduled import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt index e2c4dfc7..1f958e5a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt @@ -19,6 +19,7 @@ import com.keylesspalace.tusky.* import com.keylesspalace.tusky.components.compose.ComposeActivity import com.keylesspalace.tusky.components.instancemute.InstanceListActivity import com.keylesspalace.tusky.components.report.ReportActivity +import com.keylesspalace.tusky.components.scheduled.ScheduledTootActivity import com.keylesspalace.tusky.components.search.SearchActivity import dagger.Module import dagger.android.ContributesAndroidInjector From 04b81c5240fcd3a19cdafc9745609942a6b6ba4f Mon Sep 17 00:00:00 2001 From: Conny Duck Date: Sun, 22 Dec 2019 11:55:26 +0100 Subject: [PATCH 03/10] improve layout names --- .../scheduled/ScheduledTootActivity.kt | 35 +++++++++---------- .../res/layout/activity_scheduled_toot.xml | 8 ++--- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt index 19000fab..51d0954c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt @@ -5,7 +5,6 @@ import android.content.Intent import android.os.Bundle import android.view.View import android.view.MenuItem -import androidx.appcompat.widget.Toolbar import androidx.lifecycle.Lifecycle import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -23,6 +22,7 @@ import com.uber.autodispose.AutoDispose.autoDisposable import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.android.synthetic.main.activity_scheduled_toot.* +import kotlinx.android.synthetic.main.toolbar_basic.* import okhttp3.ResponseBody import retrofit2.Call import retrofit2.Callback @@ -50,25 +50,22 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { super.onCreate(savedInstanceState) setContentView(R.layout.activity_scheduled_toot) - val toolbar = findViewById(R.id.toolbar) - setSupportActionBar(toolbar) - val bar = supportActionBar - if (bar != null) { - bar.title = getString(R.string.title_scheduled_toot) - bar.setDisplayHomeAsUpEnabled(true) - bar.setDisplayShowHomeEnabled(true) + supportActionBar?.run { + title = getString(R.string.title_scheduled_toot) + setDisplayHomeAsUpEnabled(true) + setDisplayShowHomeEnabled(true) } - swipe_refresh_layout.setOnRefreshListener(this::refreshStatuses) + swipeRefreshLayout.setOnRefreshListener(this::refreshStatuses) - scheduled_toot_list.setHasFixedSize(true) + scheduledTootList.setHasFixedSize(true) val layoutManager = LinearLayoutManager(this) - scheduled_toot_list.layoutManager = layoutManager + scheduledTootList.layoutManager = layoutManager val divider = DividerItemDecoration(this, layoutManager.orientation) - scheduled_toot_list.addItemDecoration(divider) + scheduledTootList.addItemDecoration(divider) adapter = ScheduledTootAdapter(this) - scheduled_toot_list.adapter = adapter + scheduledTootList.adapter = adapter loadStatuses() @@ -93,11 +90,11 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { } fun loadStatuses() { - progress_bar.visibility = View.VISIBLE + progressBar.visibility = View.VISIBLE mastodonApi.scheduledStatuses() .enqueue(object : Callback> { override fun onResponse(call: Call>, response: Response>) { - progress_bar.visibility = View.GONE + progressBar.visibility = View.GONE if (response.body().isNullOrEmpty()) { errorMessageView.show() errorMessageView.setup(R.drawable.elephant_friend_empty, R.string.message_empty, @@ -108,7 +105,7 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { } override fun onFailure(call: Call>, t: Throwable) { - progress_bar.visibility = View.GONE + progressBar.visibility = View.GONE errorMessageView.show() errorMessageView.setup(R.drawable.elephant_error, R.string.error_generic) { errorMessageView.hide() @@ -119,11 +116,11 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { } private fun refreshStatuses() { - swipe_refresh_layout.isRefreshing = true + swipeRefreshLayout.isRefreshing = true mastodonApi.scheduledStatuses() .enqueue(object : Callback> { override fun onResponse(call: Call>, response: Response>) { - swipe_refresh_layout.isRefreshing = false + swipeRefreshLayout.isRefreshing = false if (response.body().isNullOrEmpty()) { errorMessageView.show() errorMessageView.setup(R.drawable.elephant_friend_empty, R.string.message_empty, @@ -134,7 +131,7 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { } override fun onFailure(call: Call>, t: Throwable) { - swipe_refresh_layout.isRefreshing = false + swipeRefreshLayout.isRefreshing = false } }) } diff --git a/app/src/main/res/layout/activity_scheduled_toot.xml b/app/src/main/res/layout/activity_scheduled_toot.xml index 937c2db3..e0f1af0c 100644 --- a/app/src/main/res/layout/activity_scheduled_toot.xml +++ b/app/src/main/res/layout/activity_scheduled_toot.xml @@ -2,7 +2,7 @@ @@ -15,7 +15,7 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior"> From 12a04dfb080a8d480ab1be6ae4491dafdb10108d Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 30 Dec 2019 20:40:27 +0100 Subject: [PATCH 04/10] move to androidx paging --- .../scheduled/ScheduledTootActivity.kt | 104 +++++++----------- .../scheduled/ScheduledTootAdapter.kt | 52 +++++---- .../scheduled/ScheduledTootDataSource.kt | 87 +++++++++++++++ .../scheduled/ScheduledTootViewModel.kt | 46 ++++++++ .../keylesspalace/tusky/di/NetworkModule.kt | 2 +- .../tusky/di/ViewModelFactory.kt | 6 + .../tusky/network/MastodonApi.kt | 7 +- .../res/layout/activity_scheduled_toot.xml | 24 ++-- 8 files changed, 224 insertions(+), 104 deletions(-) create mode 100644 app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootDataSource.kt create mode 100644 app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt index 51d0954c..04678cf2 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt @@ -3,9 +3,10 @@ package com.keylesspalace.tusky.components.scheduled import android.content.Context import android.content.Intent import android.os.Bundle -import android.view.View import android.view.MenuItem import androidx.lifecycle.Lifecycle +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.keylesspalace.tusky.BaseActivity @@ -14,8 +15,9 @@ import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.StatusScheduledEvent import com.keylesspalace.tusky.components.compose.ComposeActivity import com.keylesspalace.tusky.di.Injectable +import com.keylesspalace.tusky.di.ViewModelFactory import com.keylesspalace.tusky.entity.ScheduledStatus -import com.keylesspalace.tusky.network.MastodonApi +import com.keylesspalace.tusky.util.Status import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.show import com.uber.autodispose.AutoDispose.autoDisposable @@ -23,13 +25,8 @@ import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.android.synthetic.main.activity_scheduled_toot.* import kotlinx.android.synthetic.main.toolbar_basic.* -import okhttp3.ResponseBody -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response import javax.inject.Inject - class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { companion object { @@ -41,10 +38,12 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { lateinit var adapter: ScheduledTootAdapter - @Inject - lateinit var mastodonApi: MastodonApi @Inject lateinit var eventHub: EventHub + @Inject + lateinit var viewModelFactory: ViewModelFactory + + lateinit var viewModel: ScheduledTootViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -67,6 +66,8 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { adapter = ScheduledTootAdapter(this) scheduledTootList.adapter = adapter + viewModel = ViewModelProvider(this, viewModelFactory)[ScheduledTootViewModel::class.java] + loadStatuses() eventHub.events @@ -90,55 +91,42 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { } fun loadStatuses() { - progressBar.visibility = View.VISIBLE - mastodonApi.scheduledStatuses() - .enqueue(object : Callback> { - override fun onResponse(call: Call>, response: Response>) { - progressBar.visibility = View.GONE - if (response.body().isNullOrEmpty()) { - errorMessageView.show() - errorMessageView.setup(R.drawable.elephant_friend_empty, R.string.message_empty, - null) - } else { - show(response.body()!!) - } - } + viewModel.data.observe(this, Observer { + adapter.submitList(it) + }) - override fun onFailure(call: Call>, t: Throwable) { - progressBar.visibility = View.GONE - errorMessageView.show() - errorMessageView.setup(R.drawable.elephant_error, R.string.error_generic) { - errorMessageView.hide() - loadStatuses() - } + viewModel.networkState.observe(this, Observer { (status) -> + when(status) { + Status.SUCCESS -> { + progressBar.hide() + swipeRefreshLayout.isRefreshing = false + errorMessageView.hide() + } + Status.RUNNING -> { + errorMessageView.hide() + if(viewModel.data.value?.loadedCount ?: 0 > 0) { + swipeRefreshLayout.isRefreshing = true + } else { + progressBar.show() } - }) + } + Status.FAILED -> { + if(viewModel.data.value?.loadedCount ?: 0 >= 0) { + progressBar.hide() + swipeRefreshLayout.isRefreshing = false + errorMessageView.setup(R.drawable.elephant_error, R.string.error_generic) { + refreshStatuses() + } + errorMessageView.show() + } + } + } + + }) } private fun refreshStatuses() { - swipeRefreshLayout.isRefreshing = true - mastodonApi.scheduledStatuses() - .enqueue(object : Callback> { - override fun onResponse(call: Call>, response: Response>) { - swipeRefreshLayout.isRefreshing = false - if (response.body().isNullOrEmpty()) { - errorMessageView.show() - errorMessageView.setup(R.drawable.elephant_friend_empty, R.string.message_empty, - null) - } else { - show(response.body()!!) - } - } - - override fun onFailure(call: Call>, t: Throwable) { - swipeRefreshLayout.isRefreshing = false - } - }) - } - - fun show(statuses: List) { - adapter.setItems(statuses) - adapter.notifyDataSetChanged() + viewModel.reload() } override fun edit(position: Int, item: ScheduledStatus?) { @@ -162,15 +150,7 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { if (item == null) { return } - mastodonApi.deleteScheduledStatus(item.id) - .enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - adapter.removeItem(position) - } - override fun onFailure(call: Call, t: Throwable) { - - } - }) + viewModel.deleteScheduledStatus(item) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt index 4c07ea18..04a36c6e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt @@ -20,6 +20,8 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageButton import android.widget.TextView +import androidx.paging.PagedListAdapter +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.keylesspalace.tusky.R import com.keylesspalace.tusky.entity.ScheduledStatus @@ -31,9 +33,18 @@ interface ScheduledTootAction { class ScheduledTootAdapter( val listener: ScheduledTootAction -) : RecyclerView.Adapter() { +) : PagedListAdapter( + object: DiffUtil.ItemCallback(){ + override fun areItemsTheSame(oldItem: ScheduledStatus, newItem: ScheduledStatus): Boolean { + return oldItem.id == newItem.id + } - private var items: MutableList = mutableListOf() + override fun areContentsTheSame(oldItem: ScheduledStatus, newItem: ScheduledStatus): Boolean { + return oldItem == newItem + } + + } +) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TootViewHolder { val view = LayoutInflater.from(parent.context) @@ -42,25 +53,12 @@ class ScheduledTootAdapter( } override fun onBindViewHolder(viewHolder: TootViewHolder, position: Int) { - viewHolder.bind(items[position]) - } - - override fun getItemCount() = items.size - - fun setItems(newItems: List) { - items = newItems.toMutableList() - notifyDataSetChanged() - } - - fun removeItem(position: Int): ScheduledStatus? { - if (position < 0 || position >= items.size) { - return null + getItem(position)?.let{ + viewHolder.bind(it) } - val toot = items.removeAt(position) - notifyItemRemoved(position) - return toot } + inner class TootViewHolder(view: View) : RecyclerView.ViewHolder(view) { private val text: TextView = view.findViewById(R.id.text) @@ -70,15 +68,15 @@ class ScheduledTootAdapter( fun bind(item: ScheduledStatus) { edit.isEnabled = true delete.isEnabled = true - text.text = item.params.text - edit.setOnClickListener { v: View -> - v.isEnabled = false - listener.edit(adapterPosition, item) - } - delete.setOnClickListener { v: View -> - v.isEnabled = false - listener.delete(adapterPosition, item) - } + text.text = item.params.text + edit.setOnClickListener { v: View -> + v.isEnabled = false + listener.edit(adapterPosition, item) + } + delete.setOnClickListener { v: View -> + v.isEnabled = false + listener.delete(adapterPosition, item) + } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootDataSource.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootDataSource.kt new file mode 100644 index 00000000..78f59084 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootDataSource.kt @@ -0,0 +1,87 @@ +package com.keylesspalace.tusky.components.scheduled + +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.paging.DataSource +import androidx.paging.ItemKeyedDataSource +import com.keylesspalace.tusky.entity.ScheduledStatus +import com.keylesspalace.tusky.network.MastodonApi +import com.keylesspalace.tusky.util.NetworkState +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.addTo + +class ScheduledTootDataSourceFactory( + private val mastodonApi: MastodonApi, + private val disposables: CompositeDisposable +): DataSource.Factory() { + + private val scheduledTootsCache = mutableListOf() + + private var dataSource: ScheduledTootDataSource? = null + + val networkState = MutableLiveData() + + override fun create(): DataSource { + return ScheduledTootDataSource(mastodonApi, disposables, scheduledTootsCache, networkState).also { + dataSource = it + } + } + + fun reload() { + scheduledTootsCache.clear() + dataSource?.invalidate() + } + + fun remove(status: ScheduledStatus) { + scheduledTootsCache.remove(status) + dataSource?.invalidate() + } + +} + + +class ScheduledTootDataSource( + private val mastodonApi: MastodonApi, + private val disposables: CompositeDisposable, + private val scheduledTootsCache: MutableList, + private val networkState: MutableLiveData +): ItemKeyedDataSource() { + override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) { + if(scheduledTootsCache.isNotEmpty()) { + callback.onResult(scheduledTootsCache.toList()) + } else { + networkState.postValue(NetworkState.LOADING) + mastodonApi.scheduledStatuses(limit = params.requestedLoadSize) + .subscribe({ newData -> + scheduledTootsCache.addAll(newData) + callback.onResult(newData) + networkState.postValue(NetworkState.LOADED) + }, { throwable -> + Log.w("ScheduledTootDataSource", "Error loading scheduled statuses", throwable) + networkState.postValue(NetworkState.error(throwable.message)) + }) + .addTo(disposables) + } + } + + override fun loadAfter(params: LoadParams, callback: LoadCallback) { + mastodonApi.scheduledStatuses(limit = params.requestedLoadSize, maxId = params.key) + .subscribe({ newData -> + scheduledTootsCache.addAll(newData) + callback.onResult(newData) + }, { throwable -> + Log.w("ScheduledTootDataSource", "Error loading scheduled statuses", throwable) + networkState.postValue(NetworkState.error(throwable.message)) + }) + .addTo(disposables) + } + + override fun loadBefore(params: LoadParams, callback: LoadCallback) { + // we are always loading from beginning to end + } + + override fun getKey(item: ScheduledStatus): String { + return item.id + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt new file mode 100644 index 00000000..97946de3 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt @@ -0,0 +1,46 @@ +package com.keylesspalace.tusky.components.scheduled + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.paging.Config +import androidx.paging.toLiveData +import com.keylesspalace.tusky.entity.ScheduledStatus +import com.keylesspalace.tusky.network.MastodonApi +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.addTo +import javax.inject.Inject + +class ScheduledTootViewModel @Inject constructor( + val mastodonApi: MastodonApi +): ViewModel() { + + private val disposables = CompositeDisposable() + + private val dataSourceFactory = ScheduledTootDataSourceFactory(mastodonApi, disposables) + + val data = dataSourceFactory.toLiveData( + config = Config(pageSize = 20, initialLoadSizeHint = 20, enablePlaceholders = false) + ) + + val networkState = dataSourceFactory.networkState + + fun reload() { + dataSourceFactory.reload() + } + + fun deleteScheduledStatus(status: ScheduledStatus) { + mastodonApi.deleteScheduledStatus(status.id) + .subscribe({ + dataSourceFactory.remove(status) + },{ throwable -> + Log.w("ScheduledTootViewModel", "Error deleting scheduled status", throwable) + }) + .addTo(disposables) + + } + + override fun onCleared() { + disposables.clear() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt index 26309be5..d7f81be7 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt @@ -77,7 +77,7 @@ class NetworkModule { .apply { addInterceptor(InstanceSwitchAuthInterceptor(accountManager)) if (BuildConfig.DEBUG) { - addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC }) + addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }) } } .build() diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ViewModelFactory.kt b/app/src/main/java/com/keylesspalace/tusky/di/ViewModelFactory.kt index 8381d526..f4929463 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/ViewModelFactory.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/ViewModelFactory.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModelProvider import com.keylesspalace.tusky.components.compose.ComposeViewModel import com.keylesspalace.tusky.components.conversation.ConversationsViewModel import com.keylesspalace.tusky.components.report.ReportViewModel +import com.keylesspalace.tusky.components.scheduled.ScheduledTootViewModel import com.keylesspalace.tusky.components.search.SearchViewModel import com.keylesspalace.tusky.viewmodel.AccountViewModel import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel @@ -79,5 +80,10 @@ abstract class ViewModelModule { @ViewModelKey(ComposeViewModel::class) internal abstract fun composeViewModel(viewModel: ComposeViewModel): ViewModel + @Binds + @IntoMap + @ViewModelKey(ScheduledTootViewModel::class) + internal abstract fun scheduledTootViewModel(viewModel: ScheduledTootViewModel): ViewModel + //Add more ViewModels here } \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt index 65d096e8..da61cb6a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt +++ b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt @@ -201,12 +201,15 @@ interface MastodonApi { ): Single @GET("api/v1/scheduled_statuses") - fun scheduledStatuses(): Call> + fun scheduledStatuses( + @Query("limit") limit: Int? = null, + @Query("max_id") maxId: String? = null + ): Single> @DELETE("api/v1/scheduled_statuses/{id}") fun deleteScheduledStatus( @Path("id") scheduledStatusId: String - ): Call + ): Single @GET("api/v1/accounts/verify_credentials") fun accountVerifyCredentials(): Single diff --git a/app/src/main/res/layout/activity_scheduled_toot.xml b/app/src/main/res/layout/activity_scheduled_toot.xml index e0f1af0c..373a519a 100644 --- a/app/src/main/res/layout/activity_scheduled_toot.xml +++ b/app/src/main/res/layout/activity_scheduled_toot.xml @@ -23,6 +23,18 @@ app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + + - - - - - - \ No newline at end of file From 7aff41b89c7cff228b08ac07e20c9b4d1ba0d3d8 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 30 Dec 2019 20:48:01 +0100 Subject: [PATCH 05/10] clean up code --- .../scheduled/ScheduledTootActivity.kt | 78 ++++++------------- .../scheduled/ScheduledTootAdapter.kt | 8 +- .../scheduled/ScheduledTootViewModel.kt | 17 +++- 3 files changed, 44 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt index 04678cf2..752cd91b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt @@ -4,15 +4,12 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.MenuItem -import androidx.lifecycle.Lifecycle import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.R -import com.keylesspalace.tusky.appstore.EventHub -import com.keylesspalace.tusky.appstore.StatusScheduledEvent import com.keylesspalace.tusky.components.compose.ComposeActivity import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.ViewModelFactory @@ -20,31 +17,19 @@ import com.keylesspalace.tusky.entity.ScheduledStatus import com.keylesspalace.tusky.util.Status import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.show -import com.uber.autodispose.AutoDispose.autoDisposable -import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from -import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.android.synthetic.main.activity_scheduled_toot.* import kotlinx.android.synthetic.main.toolbar_basic.* import javax.inject.Inject class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { - companion object { - @JvmStatic - fun newIntent(context: Context): Intent { - return Intent(context, ScheduledTootActivity::class.java) - } - } - - lateinit var adapter: ScheduledTootAdapter - - @Inject - lateinit var eventHub: EventHub @Inject lateinit var viewModelFactory: ViewModelFactory lateinit var viewModel: ScheduledTootViewModel + private val adapter = ScheduledTootAdapter(this) + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_scheduled_toot) @@ -59,38 +44,13 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { swipeRefreshLayout.setOnRefreshListener(this::refreshStatuses) scheduledTootList.setHasFixedSize(true) - val layoutManager = LinearLayoutManager(this) - scheduledTootList.layoutManager = layoutManager - val divider = DividerItemDecoration(this, layoutManager.orientation) + scheduledTootList.layoutManager = LinearLayoutManager(this) + val divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL) scheduledTootList.addItemDecoration(divider) - adapter = ScheduledTootAdapter(this) scheduledTootList.adapter = adapter viewModel = ViewModelProvider(this, viewModelFactory)[ScheduledTootViewModel::class.java] - loadStatuses() - - eventHub.events - .observeOn(AndroidSchedulers.mainThread()) - .`as`(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY))) - .subscribe { event -> - if (event is StatusScheduledEvent) { - refreshStatuses() - } - } - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - android.R.id.home -> { - onBackPressed() - return true - } - } - return super.onOptionsItemSelected(item) - } - - fun loadStatuses() { viewModel.data.observe(this, Observer { adapter.submitList(it) }) @@ -123,16 +83,24 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { } }) + + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> { + onBackPressed() + return true + } + } + return super.onOptionsItemSelected(item) } private fun refreshStatuses() { viewModel.reload() } - override fun edit(position: Int, item: ScheduledStatus?) { - if (item == null) { - return - } + override fun edit(item: ScheduledStatus) { val intent = ComposeActivity.startIntent(this, ComposeActivity.ComposeOptions( tootText = item.params.text, contentWarning = item.params.spoilerText, @@ -143,14 +111,16 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { sensitive = item.params.sensitive )) startActivity(intent) - delete(position, item) } - override fun delete(position: Int, item: ScheduledStatus?) { - if (item == null) { - return - } - + override fun delete(item: ScheduledStatus) { viewModel.deleteScheduledStatus(item) } + + companion object { + @JvmStatic + fun newIntent(context: Context): Intent { + return Intent(context, ScheduledTootActivity::class.java) + } + } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt index 04a36c6e..59310c40 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt @@ -27,8 +27,8 @@ import com.keylesspalace.tusky.R import com.keylesspalace.tusky.entity.ScheduledStatus interface ScheduledTootAction { - fun edit(position: Int, item: ScheduledStatus?) - fun delete(position: Int, item: ScheduledStatus?) + fun edit(item: ScheduledStatus) + fun delete(item: ScheduledStatus) } class ScheduledTootAdapter( @@ -71,11 +71,11 @@ class ScheduledTootAdapter( text.text = item.params.text edit.setOnClickListener { v: View -> v.isEnabled = false - listener.edit(adapterPosition, item) + listener.edit(item) } delete.setOnClickListener { v: View -> v.isEnabled = false - listener.delete(adapterPosition, item) + listener.delete(item) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt index 97946de3..fcfcb5a7 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt @@ -4,14 +4,18 @@ import android.util.Log import androidx.lifecycle.ViewModel import androidx.paging.Config import androidx.paging.toLiveData +import com.keylesspalace.tusky.appstore.EventHub +import com.keylesspalace.tusky.appstore.StatusScheduledEvent import com.keylesspalace.tusky.entity.ScheduledStatus import com.keylesspalace.tusky.network.MastodonApi +import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo import javax.inject.Inject class ScheduledTootViewModel @Inject constructor( - val mastodonApi: MastodonApi + val mastodonApi: MastodonApi, + val eventHub: EventHub ): ViewModel() { private val disposables = CompositeDisposable() @@ -24,6 +28,17 @@ class ScheduledTootViewModel @Inject constructor( val networkState = dataSourceFactory.networkState + init { + eventHub.events + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { event -> + if (event is StatusScheduledEvent) { + reload() + } + } + .addTo(disposables) + } + fun reload() { dataSourceFactory.reload() } From 42d2a4798fe760d8cd76c597785e1f3b8e3d9cba Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 30 Dec 2019 20:54:00 +0100 Subject: [PATCH 06/10] color the SwipeRefreshLayout --- .../tusky/components/scheduled/ScheduledTootActivity.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt index 752cd91b..7456c473 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt @@ -15,6 +15,7 @@ import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.ViewModelFactory import com.keylesspalace.tusky.entity.ScheduledStatus import com.keylesspalace.tusky.util.Status +import com.keylesspalace.tusky.util.ThemeUtils import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.show import kotlinx.android.synthetic.main.activity_scheduled_toot.* @@ -42,6 +43,9 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { } swipeRefreshLayout.setOnRefreshListener(this::refreshStatuses) + swipeRefreshLayout.setColorSchemeResources(R.color.tusky_blue) + swipeRefreshLayout.setProgressBackgroundColorSchemeColor( + ThemeUtils.getColor(this, android.R.attr.colorBackground)) scheduledTootList.setHasFixedSize(true) scheduledTootList.layoutManager = LinearLayoutManager(this) From 7c3f19a07ec302cfe6c6d6db13d8039e697fb1d4 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 30 Dec 2019 21:01:38 +0100 Subject: [PATCH 07/10] add empty screen message --- .../tusky/components/scheduled/ScheduledTootActivity.kt | 7 ++++++- .../com/keylesspalace/tusky/view/BackgroundMessageView.kt | 2 +- app/src/main/res/values/strings.xml | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt index 7456c473..0ec59cec 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt @@ -64,7 +64,12 @@ class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { Status.SUCCESS -> { progressBar.hide() swipeRefreshLayout.isRefreshing = false - errorMessageView.hide() + if(viewModel.data.value?.loadedCount == 0) { + errorMessageView.setup(R.drawable.elephant_friend_empty, R.string.no_scheduled_status) + errorMessageView.show() + } else { + errorMessageView.hide() + } } Status.RUNNING -> { errorMessageView.hide() diff --git a/app/src/main/java/com/keylesspalace/tusky/view/BackgroundMessageView.kt b/app/src/main/java/com/keylesspalace/tusky/view/BackgroundMessageView.kt index 1b73e6f7..e39566f4 100644 --- a/app/src/main/java/com/keylesspalace/tusky/view/BackgroundMessageView.kt +++ b/app/src/main/java/com/keylesspalace/tusky/view/BackgroundMessageView.kt @@ -37,7 +37,7 @@ class BackgroundMessageView @JvmOverloads constructor( * If [clickListener] is `null` then the button will be hidden. */ fun setup(@DrawableRes imageRes: Int, @StringRes messageRes: Int, - clickListener: ((v: View) -> Unit)?) { + clickListener: ((v: View) -> Unit)? = null) { messageTextView.setText(messageRes) messageTextView.setCompoundDrawablesWithIntrinsicBounds(0, imageRes, 0, 0) button.setOnClickListener(clickListener) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ede742d..fb3dc5ef 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -545,4 +545,6 @@ Edit Error looking up post %s + You don\'t have any scheduled statuses. + From 3f00b47d0cec76631fae9415383ce7c06a4a8b91 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 30 Dec 2019 21:05:03 +0100 Subject: [PATCH 08/10] remove debug logging --- app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt index d7f81be7..26309be5 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt @@ -77,7 +77,7 @@ class NetworkModule { .apply { addInterceptor(InstanceSwitchAuthInterceptor(accountManager)) if (BuildConfig.DEBUG) { - addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }) + addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC }) } } .build() From 3a80ab727a0a76417771672fa98b604b8bf925f1 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 30 Dec 2019 21:09:10 +0100 Subject: [PATCH 09/10] add license headers --- .../components/scheduled/ScheduledTootActivity.kt | 15 +++++++++++++++ .../scheduled/ScheduledTootDataSource.kt | 15 +++++++++++++++ .../scheduled/ScheduledTootViewModel.kt | 15 +++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt index 0ec59cec..c44a0889 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt @@ -1,3 +1,18 @@ +/* Copyright 2019 Tusky Contributors + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tusky; if not, + * see . */ + package com.keylesspalace.tusky.components.scheduled import android.content.Context diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootDataSource.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootDataSource.kt index 78f59084..6c9ba31b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootDataSource.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootDataSource.kt @@ -1,3 +1,18 @@ +/* Copyright 2019 Tusky Contributors + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tusky; if not, + * see . */ + package com.keylesspalace.tusky.components.scheduled import android.util.Log diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt index fcfcb5a7..3d40e0b2 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt @@ -1,3 +1,18 @@ +/* Copyright 2019 Tusky Contributors + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tusky; if not, + * see . */ + package com.keylesspalace.tusky.components.scheduled import android.util.Log From 283e9d0ad914e9e9075543f47f84a5c18d47c317 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Tue, 31 Dec 2019 13:57:24 +0100 Subject: [PATCH 10/10] address PR feedback --- .../tusky/components/compose/ComposeViewModel.kt | 13 ------------- .../scheduled/ScheduledTootActivity.kt | 2 +- .../components/scheduled/ScheduledTootAdapter.kt | 4 ++-- .../scheduled/ScheduledTootViewModel.kt | 13 ++++--------- .../keylesspalace/tusky/util/RxAwareViewModel.kt | 16 ++++++++++++++++ 5 files changed, 23 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/com/keylesspalace/tusky/util/RxAwareViewModel.kt diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt index cbcb29ce..94613861 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt @@ -21,7 +21,6 @@ import androidx.core.net.toUri import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModel import com.keylesspalace.tusky.adapter.ComposeAutoCompleteAdapter import com.keylesspalace.tusky.components.compose.ComposeActivity.QueuedMedia import com.keylesspalace.tusky.components.search.SearchType @@ -34,23 +33,11 @@ import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.service.ServiceClient import com.keylesspalace.tusky.service.TootToSend import com.keylesspalace.tusky.util.* -import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable import io.reactivex.rxkotlin.Singles import java.util.* import javax.inject.Inject -open class RxAwareViewModel : ViewModel() { - private val disposables = CompositeDisposable() - - fun Disposable.autoDispose() = disposables.add(this) - - override fun onCleared() { - super.onCleared() - disposables.clear() - } -} - /** * Throw when trying to add an image when video is already present or the other way around */ diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt index c44a0889..17682ad3 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootActivity.kt @@ -37,7 +37,7 @@ import kotlinx.android.synthetic.main.activity_scheduled_toot.* import kotlinx.android.synthetic.main.toolbar_basic.* import javax.inject.Inject -class ScheduledTootActivity : BaseActivity(), ScheduledTootAction, Injectable { +class ScheduledTootActivity : BaseActivity(), ScheduledTootActionListener, Injectable { @Inject lateinit var viewModelFactory: ViewModelFactory diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt index 59310c40..ea12d1ff 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootAdapter.kt @@ -26,13 +26,13 @@ import androidx.recyclerview.widget.RecyclerView import com.keylesspalace.tusky.R import com.keylesspalace.tusky.entity.ScheduledStatus -interface ScheduledTootAction { +interface ScheduledTootActionListener { fun edit(item: ScheduledStatus) fun delete(item: ScheduledStatus) } class ScheduledTootAdapter( - val listener: ScheduledTootAction + val listener: ScheduledTootActionListener ) : PagedListAdapter( object: DiffUtil.ItemCallback(){ override fun areItemsTheSame(oldItem: ScheduledStatus, newItem: ScheduledStatus): Boolean { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt index 3d40e0b2..4d531a45 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledTootViewModel.kt @@ -23,6 +23,7 @@ import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.StatusScheduledEvent import com.keylesspalace.tusky.entity.ScheduledStatus import com.keylesspalace.tusky.network.MastodonApi +import com.keylesspalace.tusky.util.RxAwareViewModel import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo @@ -31,9 +32,7 @@ import javax.inject.Inject class ScheduledTootViewModel @Inject constructor( val mastodonApi: MastodonApi, val eventHub: EventHub -): ViewModel() { - - private val disposables = CompositeDisposable() +): RxAwareViewModel() { private val dataSourceFactory = ScheduledTootDataSourceFactory(mastodonApi, disposables) @@ -51,7 +50,7 @@ class ScheduledTootViewModel @Inject constructor( reload() } } - .addTo(disposables) + .autoDispose() } fun reload() { @@ -65,12 +64,8 @@ class ScheduledTootViewModel @Inject constructor( },{ throwable -> Log.w("ScheduledTootViewModel", "Error deleting scheduled status", throwable) }) - .addTo(disposables) + .autoDispose() } - override fun onCleared() { - disposables.clear() - } - } \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/util/RxAwareViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/util/RxAwareViewModel.kt new file mode 100644 index 00000000..2ad4b825 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/util/RxAwareViewModel.kt @@ -0,0 +1,16 @@ +package com.keylesspalace.tusky.util + +import androidx.lifecycle.ViewModel +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable + +open class RxAwareViewModel : ViewModel() { + val disposables = CompositeDisposable() + + fun Disposable.autoDispose() = disposables.add(this) + + override fun onCleared() { + super.onCleared() + disposables.clear() + } +} \ No newline at end of file