Gitlab@AEI Hannover will go down for maintenance on 2020-09-21 at 4:00 UTC. The service will be unavailable for up to 24 hours. If you have questions about this please contact atlas_admin@aei.mpg.de

Unverified Commit 8b553bd4 authored by Vitalii Koshura's avatar Vitalii Koshura Committed by GitHub

Merge pull request #3884 from Isira-Seneviratne/Use_RecyclerView_in_batch_conflict

[Android] Use RecyclerView in BatchConflictListActivity.
parents 45fa2490 918c774b
......@@ -25,6 +25,7 @@ import android.os.IBinder
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import edu.berkeley.boinc.BOINCActivity
import edu.berkeley.boinc.R
import edu.berkeley.boinc.attach.IndividualCredentialInputFragment.IndividualCredentialInputFragmentListener
......@@ -40,7 +41,7 @@ import kotlinx.coroutines.withContext
class BatchConflictListActivity : AppCompatActivity(), IndividualCredentialInputFragmentListener {
private lateinit var binding: AttachProjectBatchConflictsLayoutBinding
private lateinit var listAdapter: BatchConflictListAdapter
private lateinit var recyclerViewAdapter: BatchConflictRecyclerViewAdapter
private var attachService: ProjectAttachService? = null
private var asIsBound = false
private var manualUrl: String? = null
......@@ -53,7 +54,7 @@ class BatchConflictListActivity : AppCompatActivity(), IndividualCredentialInput
Log.d(Logging.TAG, "BatchConflictListActivity ClientStatusChange - onReceive()")
}
if (asIsBound) {
listAdapter.notifyDataSetChanged()
recyclerViewAdapter.notifyDataSetChanged()
}
}
}
......@@ -77,9 +78,12 @@ class BatchConflictListActivity : AppCompatActivity(), IndividualCredentialInput
// retrieve data
val results = attachService!!.selectedProjects
listAdapter = BatchConflictListAdapter(this@BatchConflictListActivity, R.id.list_view,
results, supportFragmentManager)
binding.listView.adapter = listAdapter
recyclerViewAdapter = BatchConflictRecyclerViewAdapter(this@BatchConflictListActivity,
results)
binding.recyclerView.apply {
adapter = recyclerViewAdapter
layoutManager = LinearLayoutManager(this@BatchConflictListActivity)
}
if (Logging.DEBUG) {
Log.d(Logging.TAG, "BatchConflictListActivity setup list with " + results.size + " elements.")
}
......@@ -182,7 +186,7 @@ class BatchConflictListActivity : AppCompatActivity(), IndividualCredentialInput
if (asIsBound) {
project.result = RESULT_ONGOING
// adapt layout to changed state
listAdapter.notifyDataSetChanged()
recyclerViewAdapter.notifyDataSetChanged()
} else {
if (Logging.ERROR) {
Log.e(Logging.TAG, "attachProject(): service not bound, cancel.")
......@@ -203,6 +207,6 @@ class BatchConflictListActivity : AppCompatActivity(), IndividualCredentialInput
}
// adapt layout to changed state
listAdapter.notifyDataSetChanged()
recyclerViewAdapter.notifyDataSetChanged()
}
}
/*
* This file is part of BOINC.
* http://boinc.berkeley.edu
* Copyright (C) 2020 University of California
*
* BOINC is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* BOINC 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with BOINC. If not, see <http://www.gnu.org/licenses/>.
*/
package edu.berkeley.boinc.attach;
import android.app.Activity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentManager;
import java.util.List;
import edu.berkeley.boinc.R;
import edu.berkeley.boinc.attach.ProjectAttachService.ProjectAttachWrapper;
import edu.berkeley.boinc.utils.Logging;
public class BatchConflictListAdapter extends ArrayAdapter<ProjectAttachWrapper> {
private List<ProjectAttachWrapper> entries;
private Activity activity;
private FragmentManager fmgr;
BatchConflictListAdapter(Activity a, int textViewResourceId, List<ProjectAttachWrapper> entries, FragmentManager fm) {
super(a, textViewResourceId, entries);
this.entries = entries;
this.activity = a;
this.fmgr = fm;
}
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
final ProjectAttachWrapper listItem = entries.get(position);
if(Logging.VERBOSE) {
Log.d(Logging.TAG, "BatchConflictListAdapter.getView for: " + listItem.name + " at position: " + position +
" with result: " + listItem.result);
}
LayoutInflater vi = ContextCompat.getSystemService(activity, LayoutInflater.class);
assert vi != null;
View v = vi.inflate(R.layout.attach_project_batch_conflicts_listitem, null);
TextView name = v.findViewById(R.id.name);
name.setText(listItem.name);
TextView status = v.findViewById(R.id.status);
ImageView resolveIv = v.findViewById(R.id.resolve_button_image);
ImageView statusImage = v.findViewById(R.id.status_image);
ProgressBar statusPb = v.findViewById(R.id.status_pb);
RelativeLayout itemWrapper = v.findViewById(R.id.resolve_item_wrapper);
if(listItem.result == ProjectAttachService.RESULT_SUCCESS) {
// success
status.setVisibility(View.GONE);
resolveIv.setVisibility(View.GONE);
statusPb.setVisibility(View.GONE);
statusImage.setVisibility(View.VISIBLE);
statusImage.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_baseline_check));
}
else if(listItem.result == ProjectAttachService.RESULT_ONGOING ||
listItem.result == ProjectAttachService.RESULT_UNINITIALIZED) {
// ongoing
status.setVisibility(View.GONE);
resolveIv.setVisibility(View.GONE);
statusImage.setVisibility(View.GONE);
statusPb.setVisibility(View.VISIBLE);
}
else if(listItem.result == ProjectAttachService.RESULT_READY) {
// ready
status.setVisibility(View.VISIBLE);
status.setText(listItem.getResultDescription());
resolveIv.setVisibility(View.VISIBLE);
itemWrapper.setOnClickListener(view -> {
if(Logging.DEBUG) {
Log.d(Logging.TAG, "BatchConflictListAdapter: start resolution dialog for: " + listItem.name);
}
IndividualCredentialInputFragment dialog = IndividualCredentialInputFragment.newInstance(listItem);
dialog.show(fmgr, listItem.name);
});
}
else if(listItem.result == ProjectAttachService.RESULT_CONFIG_DOWNLOAD_FAILED) {
// download failed, can not continue from here.
// if user wants to retry, need to go back to selection activity
status.setVisibility(View.VISIBLE);
status.setText(listItem.getResultDescription());
resolveIv.setVisibility(View.GONE);
statusPb.setVisibility(View.GONE);
statusImage.setVisibility(View.VISIBLE);
statusImage.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_baseline_clear));
}
else {
// failed
status.setVisibility(View.VISIBLE);
status.setText(listItem.getResultDescription());
resolveIv.setVisibility(View.VISIBLE);
itemWrapper.setOnClickListener(view -> {
if(Logging.DEBUG) {
Log.d(Logging.TAG, "BatchConflictListAdapter: start resolution dialog for: " + listItem.name);
}
IndividualCredentialInputFragment dialog = IndividualCredentialInputFragment.newInstance(listItem);
dialog.show(fmgr, listItem.name);
});
statusPb.setVisibility(View.GONE);
statusImage.setVisibility(View.VISIBLE);
statusImage.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_baseline_clear));
}
return v;
}
@Override
public int getCount() {
return entries.size();
}
}
/*
* This file is part of BOINC.
* http://boinc.berkeley.edu
* Copyright (C) 2020 University of California
*
* BOINC is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* BOINC 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with BOINC. If not, see <http://www.gnu.org/licenses/>.
*/
package edu.berkeley.boinc.attach
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
import edu.berkeley.boinc.R
import edu.berkeley.boinc.databinding.AttachProjectBatchConflictsListItemBinding
import edu.berkeley.boinc.utils.Logging
class BatchConflictRecyclerViewAdapter(
private val activity: FragmentActivity,
private val entries: List<ProjectAttachService.ProjectAttachWrapper>
): RecyclerView.Adapter<BatchConflictRecyclerViewAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = AttachProjectBatchConflictsListItemBinding.inflate(LayoutInflater.from(parent.context))
return ViewHolder(binding)
}
override fun getItemCount() = entries.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val listItem = entries[position]
if (Logging.VERBOSE) {
Log.d(Logging.TAG, "BatchConflictListAdapter.getView for: ${listItem.name} at" +
" position: $position with result: ${listItem.result}")
}
holder.name.text = listItem.name
if (listItem.result == ProjectAttachService.RESULT_SUCCESS) {
// success
holder.status.visibility = View.GONE
holder.resolveButtonImage.visibility = View.GONE
holder.statusProgressBar.visibility = View.GONE
holder.statusImage.visibility = View.VISIBLE
holder.statusImage.setImageDrawable(ContextCompat.getDrawable(activity, R.drawable.ic_baseline_check))
} else if (listItem.result == ProjectAttachService.RESULT_ONGOING ||
listItem.result == ProjectAttachService.RESULT_UNINITIALIZED) {
// ongoing
holder.status.visibility = View.GONE
holder.resolveButtonImage.visibility = View.GONE
holder.statusImage.visibility = View.GONE
holder.statusProgressBar.visibility = View.VISIBLE
} else if (listItem.result == ProjectAttachService.RESULT_READY) {
// ready
holder.status.visibility = View.VISIBLE
holder.status.text = listItem.resultDescription
holder.resolveButtonImage.visibility = View.VISIBLE
holder.resolveItemWrapper.setOnClickListener {
if (Logging.DEBUG) {
Log.d(Logging.TAG, "BatchConflictListAdapter: start resolution dialog for: " + listItem.name)
}
val dialog = IndividualCredentialInputFragment.newInstance(listItem)
dialog.show(activity.supportFragmentManager, listItem.name)
}
} else if (listItem.result == ProjectAttachService.RESULT_CONFIG_DOWNLOAD_FAILED) {
// download failed, can not continue from here.
// if user wants to retry, need to go back to selection activity
holder.status.visibility = View.VISIBLE
holder.status.text = listItem.resultDescription
holder.resolveButtonImage.visibility = View.GONE
holder.statusProgressBar.visibility = View.GONE
holder.statusImage.visibility = View.VISIBLE
holder.statusImage.setImageDrawable(ContextCompat.getDrawable(activity, R.drawable.ic_baseline_clear))
} else {
// failed
holder.status.visibility = View.VISIBLE
holder.status.text = listItem.resultDescription
holder.resolveButtonImage.visibility = View.VISIBLE
holder.resolveItemWrapper.setOnClickListener {
if (Logging.DEBUG) {
Log.d(Logging.TAG, "BatchConflictListAdapter: start resolution dialog for: " + listItem.name)
}
val dialog = IndividualCredentialInputFragment.newInstance(listItem)
dialog.show(activity.supportFragmentManager, listItem.name)
}
holder.statusProgressBar.visibility = View.GONE
holder.statusImage.visibility = View.VISIBLE
holder.statusImage.setImageDrawable(ContextCompat.getDrawable(activity, R.drawable.ic_baseline_clear))
}
}
inner class ViewHolder(binding: AttachProjectBatchConflictsListItemBinding):
RecyclerView.ViewHolder(binding.root) {
val name = binding.name
val status = binding.status
val resolveButtonImage = binding.resolveButtonImage
val statusImage = binding.statusImage
val statusProgressBar = binding.statusProgressBar
val resolveItemWrapper = binding.resolveItemWrapper
}
}
......@@ -52,9 +52,9 @@ public class IndividualCredentialInputFragment extends DialogFragment {
static IndividualCredentialInputFragment newInstance(ProjectAttachWrapper item) {
IndividualCredentialInputFragment frag = new IndividualCredentialInputFragment();
frag.projectName = item.config.getName();
frag.projectName = item.getConfig().getName();
frag.errorMessage = item.getResultDescription();
frag.forgotPwdLink = item.config.getMasterUrl() + "/get_passwd.php";
frag.forgotPwdLink = item.getConfig().getMasterUrl() + "/get_passwd.php";
frag.project = item;
return frag;
}
......@@ -93,12 +93,12 @@ public class IndividualCredentialInputFragment extends DialogFragment {
if(Logging.DEBUG) {
Log.d(Logging.TAG,
"IndividualCredentialInputFragment: register clicked, client account creation disabled: " +
project.config.getClientAccountCreationDisabled());
project.getConfig().getClientAccountCreationDisabled());
}
if(project.config.getClientAccountCreationDisabled()) {
if(project.getConfig().getClientAccountCreationDisabled()) {
// cannot register in client, open website
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(project.config.getMasterUrl()));
i.setData(Uri.parse(project.getConfig().getMasterUrl()));
startActivity(i);
}
else {
......
......@@ -305,17 +305,14 @@ class ProjectAttachService : LifecycleService() {
}
inner class ProjectAttachWrapper {
var url // URL, manually inserted, or from projectInfo
: String
var info // chosen from list
: ProjectInfo? = null
// URL, manually inserted, or from projectInfo
var url: String
// chosen from list
var info: ProjectInfo? = null
// name of project in debug messages, do not use otherwise!
@JvmField
var name: String
// has to be downloaded, available if RESULT_READY
@JvmField
var config: ProjectConfig? = null
@JvmField
var result = Companion.RESULT_UNINITIALIZED
constructor(info: ProjectInfo) {
......
......@@ -47,8 +47,9 @@
android:layout_below="@+id/logo"
android:padding="5dp"
android:background="@drawable/shape_dark_blue_background"/>
<ListView
android:id="@+id/list_view"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/desc"
......
......@@ -41,7 +41,7 @@
android:visibility="gone" />
<ProgressBar
android:id="@+id/status_pb"
android:id="@+id/status_progress_bar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment