mirror of https://github.com/tasks/tasks
Convert tag picker to Kotlin
parent
811c9497e1
commit
ef432e296c
@ -1,118 +0,0 @@
|
||||
package org.tasks.tags;
|
||||
|
||||
import static org.tasks.Strings.isNullOrEmpty;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.EditText;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnTextChanged;
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
import java.util.ArrayList;
|
||||
import javax.inject.Inject;
|
||||
import org.tasks.R;
|
||||
import org.tasks.billing.Inventory;
|
||||
import org.tasks.data.TagData;
|
||||
import org.tasks.injection.ThemedInjectingAppCompatActivity;
|
||||
import org.tasks.tags.CheckBoxTriStates.State;
|
||||
import org.tasks.themes.ColorProvider;
|
||||
import org.tasks.themes.Theme;
|
||||
import org.tasks.themes.ThemeColor;
|
||||
|
||||
@AndroidEntryPoint
|
||||
public class TagPickerActivity extends ThemedInjectingAppCompatActivity {
|
||||
|
||||
public static final String EXTRA_SELECTED = "extra_tags";
|
||||
public static final String EXTRA_PARTIALLY_SELECTED = "extra_partial";
|
||||
public static final String EXTRA_TASKS = "extra_tasks";
|
||||
|
||||
@BindView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
|
||||
@BindView(R.id.recycler_view)
|
||||
RecyclerView recyclerView;
|
||||
|
||||
@BindView(R.id.search_input)
|
||||
EditText editText;
|
||||
|
||||
@Inject Theme theme;
|
||||
@Inject Inventory inventory;
|
||||
@Inject ColorProvider colorProvider;
|
||||
|
||||
private TagPickerViewModel viewModel;
|
||||
private ArrayList<Long> taskIds;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
viewModel = new ViewModelProvider(this).get(TagPickerViewModel.class);
|
||||
Intent intent = getIntent();
|
||||
taskIds = (ArrayList<Long>) intent.getSerializableExtra(EXTRA_TASKS);
|
||||
if (savedInstanceState == null) {
|
||||
viewModel.setSelected(
|
||||
intent.getParcelableArrayListExtra(EXTRA_SELECTED),
|
||||
intent.getParcelableArrayListExtra(EXTRA_PARTIALLY_SELECTED));
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_tag_picker);
|
||||
|
||||
ButterKnife.bind(this);
|
||||
|
||||
toolbar.setNavigationIcon(R.drawable.ic_outline_arrow_back_24px);
|
||||
toolbar.setNavigationOnClickListener(v -> onBackPressed());
|
||||
|
||||
ThemeColor themeColor = theme.getThemeColor();
|
||||
themeColor.applyToStatusBarIcons(this);
|
||||
themeColor.applyToNavigationBar(this);
|
||||
themeColor.apply(toolbar);
|
||||
|
||||
TagRecyclerAdapter recyclerAdapter =
|
||||
new TagRecyclerAdapter(this, viewModel, inventory, colorProvider, this::onToggle);
|
||||
|
||||
recyclerView.setAdapter(recyclerAdapter);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
viewModel.observe(this, recyclerAdapter::submitList);
|
||||
editText.setText(viewModel.getText());
|
||||
}
|
||||
|
||||
private State onToggle(TagData tagData, Boolean checked) {
|
||||
boolean newTag = tagData.getId() == null;
|
||||
|
||||
State state = viewModel.toggle(tagData, checked);
|
||||
|
||||
if (newTag) {
|
||||
clear();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@OnTextChanged(R.id.search_input)
|
||||
void onSearch(CharSequence text) {
|
||||
viewModel.search(text.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (isNullOrEmpty(viewModel.getText())) {
|
||||
Intent data = new Intent();
|
||||
data.putExtra(EXTRA_TASKS, taskIds);
|
||||
data.putParcelableArrayListExtra(EXTRA_PARTIALLY_SELECTED, viewModel.getPartiallySelected());
|
||||
data.putParcelableArrayListExtra(EXTRA_SELECTED, viewModel.getSelected());
|
||||
setResult(RESULT_OK, data);
|
||||
finish();
|
||||
} else {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
editText.setText("");
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package org.tasks.tags
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.EditText
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnTextChanged
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import org.tasks.R
|
||||
import org.tasks.Strings.isNullOrEmpty
|
||||
import org.tasks.billing.Inventory
|
||||
import org.tasks.data.TagData
|
||||
import org.tasks.injection.ThemedInjectingAppCompatActivity
|
||||
import org.tasks.themes.ColorProvider
|
||||
import org.tasks.themes.Theme
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TagPickerActivity : ThemedInjectingAppCompatActivity() {
|
||||
@BindView(R.id.toolbar)
|
||||
lateinit var toolbar: Toolbar
|
||||
@BindView(R.id.recycler_view)
|
||||
lateinit var recyclerView: RecyclerView
|
||||
@BindView(R.id.search_input)
|
||||
lateinit var editText: EditText
|
||||
|
||||
@Inject lateinit var theme: Theme
|
||||
@Inject lateinit var inventory: Inventory
|
||||
@Inject lateinit var colorProvider: ColorProvider
|
||||
|
||||
private val viewModel: TagPickerViewModel by viewModels()
|
||||
private var taskIds: ArrayList<Long>? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val intent = intent
|
||||
taskIds = intent.getSerializableExtra(EXTRA_TASKS) as ArrayList<Long>?
|
||||
if (savedInstanceState == null) {
|
||||
viewModel.setSelected(
|
||||
intent.getParcelableArrayListExtra(EXTRA_SELECTED),
|
||||
intent.getParcelableArrayListExtra(EXTRA_PARTIALLY_SELECTED))
|
||||
}
|
||||
setContentView(R.layout.activity_tag_picker)
|
||||
ButterKnife.bind(this)
|
||||
toolbar.setNavigationIcon(R.drawable.ic_outline_arrow_back_24px)
|
||||
toolbar.setNavigationOnClickListener { onBackPressed() }
|
||||
val themeColor = theme.themeColor
|
||||
themeColor.applyToStatusBarIcons(this)
|
||||
themeColor.applyToNavigationBar(this)
|
||||
themeColor.apply(toolbar)
|
||||
val recyclerAdapter = TagRecyclerAdapter(this, viewModel, inventory, colorProvider) { tagData, vh ->
|
||||
onToggle(tagData, vh)
|
||||
}
|
||||
recyclerView.adapter = recyclerAdapter
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator?)!!.supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
viewModel.observe(this) { recyclerAdapter.submitList(it) }
|
||||
editText.setText(viewModel.text)
|
||||
}
|
||||
|
||||
private fun onToggle(tagData: TagData, vh: TagPickerViewHolder) = lifecycleScope.launch {
|
||||
val newTag = tagData.id == null
|
||||
val newState = viewModel.toggle(tagData, vh.isChecked || newTag)
|
||||
vh.updateCheckbox(newState)
|
||||
if (newTag) {
|
||||
clear()
|
||||
}
|
||||
}
|
||||
|
||||
@OnTextChanged(R.id.search_input)
|
||||
fun onSearch(text: CharSequence) {
|
||||
viewModel.search(text.toString())
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (isNullOrEmpty(viewModel.text)) {
|
||||
val data = Intent()
|
||||
data.putExtra(EXTRA_TASKS, taskIds)
|
||||
data.putParcelableArrayListExtra(EXTRA_PARTIALLY_SELECTED, viewModel.getPartiallySelected())
|
||||
data.putParcelableArrayListExtra(EXTRA_SELECTED, viewModel.getSelected())
|
||||
setResult(Activity.RESULT_OK, data)
|
||||
finish()
|
||||
} else {
|
||||
clear()
|
||||
}
|
||||
}
|
||||
|
||||
private fun clear() {
|
||||
editText.setText("")
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_SELECTED = "extra_tags"
|
||||
const val EXTRA_PARTIALLY_SELECTED = "extra_partial"
|
||||
const val EXTRA_TASKS = "extra_tasks"
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
package org.tasks.tags;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnCheckedChanged;
|
||||
import butterknife.OnClick;
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import org.tasks.R;
|
||||
import org.tasks.data.TagData;
|
||||
import org.tasks.tags.CheckBoxTriStates.State;
|
||||
import org.tasks.themes.DrawableUtil;
|
||||
|
||||
public class TagPickerViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final Context context;
|
||||
private final Function2<TagData, Boolean, State> callback;
|
||||
|
||||
@BindView(R.id.text)
|
||||
TextView text;
|
||||
|
||||
@BindView(R.id.checkbox)
|
||||
CheckBoxTriStates checkBox;
|
||||
|
||||
private TagData tagData;
|
||||
|
||||
TagPickerViewHolder(
|
||||
Context context, @NonNull View view, Function2<TagData, Boolean, State> callback) {
|
||||
super(view);
|
||||
this.callback = callback;
|
||||
|
||||
ButterKnife.bind(this, view);
|
||||
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@OnClick(R.id.tag_row)
|
||||
void onClickRow() {
|
||||
if (tagData.getId() == null) {
|
||||
callback.invoke(tagData, true);
|
||||
} else {
|
||||
checkBox.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
@OnCheckedChanged(R.id.checkbox)
|
||||
void onCheckedChanged() {
|
||||
State newState = callback.invoke(tagData, checkBox.isChecked());
|
||||
updateCheckbox(newState);
|
||||
}
|
||||
|
||||
public void bind(
|
||||
@NonNull TagData tagData, int color, @Nullable Integer icon, State state) {
|
||||
this.tagData = tagData;
|
||||
if (tagData.getId() == null) {
|
||||
text.setText(context.getString(R.string.create_new_tag, tagData.getName()));
|
||||
icon = R.drawable.ic_outline_add_24px;
|
||||
checkBox.setVisibility(View.GONE);
|
||||
} else {
|
||||
text.setText(tagData.getName());
|
||||
if (state == State.CHECKED) {
|
||||
checkBox.setChecked(true);
|
||||
} else {
|
||||
updateCheckbox(state);
|
||||
}
|
||||
if (icon == null) {
|
||||
icon = R.drawable.ic_outline_label_24px;
|
||||
}
|
||||
}
|
||||
DrawableUtil.setLeftDrawable(context, text, icon);
|
||||
DrawableUtil.setTint(DrawableUtil.getLeftDrawable(text), color);
|
||||
}
|
||||
|
||||
private void updateCheckbox(State state) {
|
||||
checkBox.setState(state, false);
|
||||
checkBox.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package org.tasks.tags
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.OnCheckedChanged
|
||||
import butterknife.OnClick
|
||||
import org.tasks.R
|
||||
import org.tasks.data.TagData
|
||||
import org.tasks.tags.CheckBoxTriStates
|
||||
import org.tasks.themes.DrawableUtil
|
||||
|
||||
class TagPickerViewHolder internal constructor(
|
||||
private val context: Context,
|
||||
view: View,
|
||||
private val callback: (TagData, TagPickerViewHolder) -> Unit
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
val isChecked: Boolean
|
||||
get() = checkBox.isChecked
|
||||
|
||||
@BindView(R.id.text)
|
||||
lateinit var text: TextView
|
||||
|
||||
@BindView(R.id.checkbox)
|
||||
lateinit var checkBox: CheckBoxTriStates
|
||||
|
||||
private var tagData: TagData? = null
|
||||
|
||||
@OnClick(R.id.tag_row)
|
||||
fun onClickRow() {
|
||||
if (tagData!!.id == null) {
|
||||
callback.invoke(tagData!!, this)
|
||||
} else {
|
||||
checkBox.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
@OnCheckedChanged(R.id.checkbox)
|
||||
fun onCheckedChanged() {
|
||||
callback.invoke(tagData!!, this)
|
||||
}
|
||||
|
||||
fun bind(
|
||||
tagData: TagData, color: Int, icon: Int?, state: CheckBoxTriStates.State) {
|
||||
var icon = icon
|
||||
this.tagData = tagData
|
||||
if (tagData.id == null) {
|
||||
text.text = context.getString(R.string.create_new_tag, tagData.name)
|
||||
icon = R.drawable.ic_outline_add_24px
|
||||
checkBox.visibility = View.GONE
|
||||
} else {
|
||||
text.text = tagData.name
|
||||
if (state == CheckBoxTriStates.State.CHECKED) {
|
||||
checkBox.isChecked = true
|
||||
} else {
|
||||
updateCheckbox(state)
|
||||
}
|
||||
if (icon == null) {
|
||||
icon = R.drawable.ic_outline_label_24px
|
||||
}
|
||||
}
|
||||
DrawableUtil.setLeftDrawable(context, text, icon)
|
||||
DrawableUtil.setTint(DrawableUtil.getLeftDrawable(text), color)
|
||||
}
|
||||
|
||||
fun updateCheckbox(state: CheckBoxTriStates.State) {
|
||||
checkBox.setState(state, false)
|
||||
checkBox.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
init {
|
||||
ButterKnife.bind(this, view)
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
package org.tasks.tags;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.AsyncListDiffer;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.List;
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import org.tasks.R;
|
||||
import org.tasks.billing.Inventory;
|
||||
import org.tasks.data.TagData;
|
||||
import org.tasks.tags.CheckBoxTriStates.State;
|
||||
import org.tasks.themes.ColorProvider;
|
||||
import org.tasks.themes.CustomIcons;
|
||||
import org.tasks.themes.ThemeColor;
|
||||
|
||||
class TagRecyclerAdapter extends RecyclerView.Adapter<TagPickerViewHolder> {
|
||||
|
||||
private final AsyncListDiffer<TagData> differ;
|
||||
private final Context context;
|
||||
private final TagPickerViewModel viewModel;
|
||||
private final Inventory inventory;
|
||||
private final ColorProvider colorProvider;
|
||||
private final Function2<TagData, Boolean, State> callback;
|
||||
|
||||
TagRecyclerAdapter(
|
||||
Context context,
|
||||
TagPickerViewModel viewModel,
|
||||
Inventory inventory,
|
||||
ColorProvider colorProvider,
|
||||
Function2<TagData, Boolean, State> callback) {
|
||||
this.context = context;
|
||||
this.viewModel = viewModel;
|
||||
this.inventory = inventory;
|
||||
this.colorProvider = colorProvider;
|
||||
this.callback = callback;
|
||||
differ = new AsyncListDiffer<>(this, new TagDiffCallback());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TagPickerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.row_tag_picker, parent, false);
|
||||
return new TagPickerViewHolder(context, view, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull TagPickerViewHolder holder, int position) {
|
||||
TagData tagData = differ.getCurrentList().get(position);
|
||||
holder.bind(tagData, getColor(tagData), getIcon(tagData), viewModel.getState(tagData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return differ.getCurrentList().size();
|
||||
}
|
||||
|
||||
private int getColor(TagData tagData) {
|
||||
if (tagData.getColor() != 0) {
|
||||
ThemeColor themeColor = colorProvider.getThemeColor(tagData.getColor(), true);
|
||||
if (inventory.purchasedThemes() || themeColor.isFree()) {
|
||||
return themeColor.getPrimaryColor();
|
||||
}
|
||||
}
|
||||
return context.getColor(R.color.icon_tint_with_alpha);
|
||||
}
|
||||
|
||||
private @Nullable Integer getIcon(TagData tagData) {
|
||||
return tagData.getIcon() < 1000 || inventory.hasPro()
|
||||
? CustomIcons.getIconResId(tagData.getIcon())
|
||||
: null;
|
||||
}
|
||||
|
||||
public void submitList(List<TagData> tagData) {
|
||||
differ.submitList(tagData);
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.tasks.tags
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.AsyncListDiffer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.tasks.R
|
||||
import org.tasks.billing.Inventory
|
||||
import org.tasks.data.TagData
|
||||
import org.tasks.themes.ColorProvider
|
||||
import org.tasks.themes.CustomIcons.getIconResId
|
||||
|
||||
internal class TagRecyclerAdapter(
|
||||
private val context: Context,
|
||||
private val viewModel: TagPickerViewModel,
|
||||
private val inventory: Inventory,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val callback: (TagData, TagPickerViewHolder) -> Unit
|
||||
) : RecyclerView.Adapter<TagPickerViewHolder>() {
|
||||
|
||||
private val differ: AsyncListDiffer<TagData> = AsyncListDiffer(this, TagDiffCallback())
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TagPickerViewHolder {
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.row_tag_picker, parent, false)
|
||||
return TagPickerViewHolder(context, view, callback)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TagPickerViewHolder, position: Int) {
|
||||
val tagData = differ.currentList[position]
|
||||
holder.bind(tagData, getColor(tagData), getIcon(tagData), viewModel.getState(tagData))
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return differ.currentList.size
|
||||
}
|
||||
|
||||
private fun getColor(tagData: TagData): Int {
|
||||
if (tagData.getColor() != 0) {
|
||||
val themeColor = colorProvider.getThemeColor(tagData.getColor()!!, true)
|
||||
if (inventory.purchasedThemes() || themeColor.isFree) {
|
||||
return themeColor.primaryColor
|
||||
}
|
||||
}
|
||||
return context.getColor(R.color.icon_tint_with_alpha)
|
||||
}
|
||||
|
||||
private fun getIcon(tagData: TagData): Int? {
|
||||
return if (tagData.getIcon()!! < 1000 || inventory.hasPro()) getIconResId(tagData.getIcon()!!) else null
|
||||
}
|
||||
|
||||
fun submitList(tagData: List<TagData>?) {
|
||||
differ.submitList(tagData)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue