Commit b32b42f6 authored by Rahadi Jalu's avatar Rahadi Jalu

Current Changes

parent 2ee4e7a9
Pipeline #145 canceled with stages
...@@ -53,18 +53,6 @@ Secara umum, pengembangan aplikasi lebih lanjut dapat dilakukan dengan langkah-l ...@@ -53,18 +53,6 @@ Secara umum, pengembangan aplikasi lebih lanjut dapat dilakukan dengan langkah-l
7. Untuk melakukan run project, tekan tombol panah hijau di bagian atas dari Android Studio. 7. Untuk melakukan run project, tekan tombol panah hijau di bagian atas dari Android Studio.
> Note: Penggunaan emulator mungkin dapat mengakibatkan aplikasi berjalan lambat. Oleh karena itu, disarankan untuk menggunakan device selama memungkinkan. > Note: Penggunaan emulator mungkin dapat mengakibatkan aplikasi berjalan lambat. Oleh karena itu, disarankan untuk menggunakan device selama memungkinkan.
## Panduan & Dokumentasi
Berikut adalah *table of content* dari panduan yang tersedia:
1. Instalasi aplikasi
- Menggunakan APK
- Run project pada Android Studio
2. Penggunaan aplikasi
- Konfigurasi Server
- User Interface pemutakhiran
- Keterkaitan Kuesioner
## Credits ## Credits
Banyak pihak yang telah dilibatkan dalam melakukan pengembangan aplikasi ini. Oleh karena itu, pengembang mengucapkan terima kasih kepada: Banyak pihak yang telah dilibatkan dalam melakukan pengembangan aplikasi ini. Oleh karena itu, pengembang mengucapkan terima kasih kepada:
......
...@@ -313,7 +313,7 @@ public class CapiInstanceActivity extends AppCompatActivity ...@@ -313,7 +313,7 @@ public class CapiInstanceActivity extends AppCompatActivity
HashMap<String, String> informations = new HashMap<>(); HashMap<String, String> informations = new HashMap<>();
File file = new File(instance.getInstanceFilePath()); File file = new File(instance.getInstanceFilePath());
InstanceValues values = XmlUtils.getInstanceValues(instance.getInstanceUuid(), file, labels); InstanceValues values = XmlUtils.getInstanceValues(instance.getInstanceUuid(), file, labels, InstanceValues.STATE_NEUTRAL);
Set<String> parsedXpaths = values.getXPaths(); Set<String> parsedXpaths = values.getXPaths();
for(String parsed : parsedXpaths) { for(String parsed : parsedXpaths) {
if(parsed.equals(titleSelected)) { if(parsed.equals(titleSelected)) {
......
package id.ac.stis.capi.lessthink.activities; package id.ac.stis.capi.lessthink.activities;
import android.content.ContentUris; import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import org.apache.commons.lang3.ArrayUtils;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import id.ac.stis.capi.R; import id.ac.stis.capi.R;
import id.ac.stis.capi.collectiva.preferences.Constants; import id.ac.stis.capi.lessthink.binders.NodeViewFactory;
import id.ac.stis.capi.lessthink.fragments.FormEntryDialogFragment; import id.ac.stis.capi.lessthink.fragments.FormEntryDialogFragment;
import id.ac.stis.capi.lessthink.fragments.InstancePreferenceFragment; import id.ac.stis.capi.lessthink.fragments.InstancePreferenceFragment;
import id.ac.stis.capi.lessthink.listeners.InstanceDownloadListener;
import id.ac.stis.capi.lessthink.listeners.InstanceListDownloadListener;
import id.ac.stis.capi.lessthink.listeners.InstanceValueListener;
import id.ac.stis.capi.lessthink.listeners.OnEntrySavedListener; import id.ac.stis.capi.lessthink.listeners.OnEntrySavedListener;
import id.ac.stis.capi.lessthink.listeners.OnTableAddButtonClickListener; import id.ac.stis.capi.lessthink.listeners.OnTableAddButtonClickListener;
import id.ac.stis.capi.lessthink.models.FormLabels; import id.ac.stis.capi.lessthink.models.FormLabels;
import id.ac.stis.capi.lessthink.models.InstanceValues; import id.ac.stis.capi.lessthink.models.InstanceValues;
import id.ac.stis.capi.lessthink.models.ModeTreeNode;
import id.ac.stis.capi.lessthink.tasks.InstanceDownloadTask;
import id.ac.stis.capi.lessthink.tasks.InstanceListDownloadTask;
import id.ac.stis.capi.lessthink.tasks.InstanceValueTask;
import id.ac.stis.capi.lessthink.utils.XmlUtils; import id.ac.stis.capi.lessthink.utils.XmlUtils;
import id.ac.stis.capi.lessthink.views.TableFooterView; import id.ac.stis.capi.lessthink.views.TableFooterView;
import id.ac.stis.capi.lessthink.views.TableHeaderView; import id.ac.stis.capi.lessthink.views.TableHeaderView;
...@@ -43,15 +53,16 @@ import id.ac.stis.capi.odk.dto.Form; ...@@ -43,15 +53,16 @@ import id.ac.stis.capi.odk.dto.Form;
import id.ac.stis.capi.odk.dto.Instance; import id.ac.stis.capi.odk.dto.Instance;
import id.ac.stis.capi.odk.listeners.DeleteInstancesListener; import id.ac.stis.capi.odk.listeners.DeleteInstancesListener;
import id.ac.stis.capi.odk.listeners.DiskSyncListener; import id.ac.stis.capi.odk.listeners.DiskSyncListener;
import id.ac.stis.capi.odk.provider.FormsProviderAPI;
import id.ac.stis.capi.odk.provider.InstanceProviderAPI; import id.ac.stis.capi.odk.provider.InstanceProviderAPI;
import id.ac.stis.capi.odk.tasks.DeleteInstancesTask; import id.ac.stis.capi.odk.tasks.DeleteInstancesTask;
import id.ac.stis.capi.odk.tasks.InstanceSyncTask; import id.ac.stis.capi.odk.tasks.InstanceSyncTask;
import id.ac.stis.capi.odk.utilities.ApplicationConstants; import me.texy.treeview.TreeNode;
import me.texy.treeview.TreeView;
import timber.log.Timber; import timber.log.Timber;
public class InstanceActivity extends AppCompatActivity implements OnEntrySavedListener, SearchView.OnQueryTextListener, public class InstanceActivity extends AppCompatActivity implements OnEntrySavedListener,
DiskSyncListener, DeleteInstancesListener{ SearchView.OnQueryTextListener, DiskSyncListener, DeleteInstancesListener,
InstanceListDownloadListener, InstanceDownloadListener, InstanceValueListener {
private static final String FORM_ID_KEY = "formid"; private static final String FORM_ID_KEY = "formid";
private static final String FORMNAME = "formname"; private static final String FORMNAME = "formname";
...@@ -65,6 +76,12 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -65,6 +76,12 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
private InstanceSyncTask instanceSyncTask; private InstanceSyncTask instanceSyncTask;
private DeleteInstancesTask deleteInstancesTask; private DeleteInstancesTask deleteInstancesTask;
private LinearLayout progressBarHolder; private LinearLayout progressBarHolder;
private FrameLayout downloadButton;
private InstanceListDownloadTask listDownloadTask;
private TextView initDataCountView;
private InstanceDownloadTask downloadTask;
private InstanceValueTask instanceValueTask;
private ProgressDialog dialog;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
...@@ -77,6 +94,8 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -77,6 +94,8 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
tableRowView = findViewById(R.id.row_view); tableRowView = findViewById(R.id.row_view);
tableFooterView = findViewById(R.id.footer_view); tableFooterView = findViewById(R.id.footer_view);
progressBarHolder = findViewById(R.id.loading_container); progressBarHolder = findViewById(R.id.loading_container);
downloadButton = findViewById(R.id.init_data_download);
initDataCountView = findViewById(R.id.init_data_count);
formId = getIntent().getStringExtra(FORM_ID_KEY); formId = getIntent().getStringExtra(FORM_ID_KEY);
formName = getIntent().getStringExtra(FORMNAME); formName = getIntent().getStringExtra(FORMNAME);
...@@ -86,9 +105,44 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -86,9 +105,44 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} }
instanceSyncTask = new InstanceSyncTask(); FormsDao formsDao = new FormsDao();
instanceSyncTask.setDiskSyncListener(this); List<Form> forms = formsDao.getFormsFromCursor(formsDao.getFormsCursorForFormId(formId));
instanceSyncTask.execute();
File file = new File(forms.get(0).getFormFilePath());
List<String> xPaths = XmlUtils.getInstanceXPathList(file, false);
labels = XmlUtils.getFormLabels(formId, file, xPaths);
tableHeaderView.setColumns(labels);
tableRowView.initView();
tableRowView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(InstanceActivity.this, "Click : " + view.getTag(), Toast.LENGTH_LONG).show();
String instanceUuid = view.getTag().toString();
// entryDialogFragment = FormEntryDialogFragment.newInstance(instanceUuid,
// FormEntryDialogFragment.MODE_EDIT, false);
entryDialogFragment = FormEntryDialogFragment.newInstance(instanceUuid, formId);
entryDialogFragment.show(getSupportFragmentManager(), instanceUuid);
entryDialogFragment.setOnEntrySavedListener(InstanceActivity.this);
//
// Intent i =new Intent(InstanceActivity.this, ListingFormEntryActivity.class);
// i.putExtra("instanceUuid", view.getTag().toString());
// startActivity(i);
}
});
tableFooterView.setOnTableAddButtonClickListener(new OnTableAddButtonClickListener() {
@Override
public void onAddButtonClick(View v) {
fillBlankForm();
}
});
listDownloadTask = new InstanceListDownloadTask(formId);
listDownloadTask.setDownloaderListener(this);
listDownloadTask.execute();
onStartLoading(); onStartLoading();
} }
...@@ -107,19 +161,24 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -107,19 +161,24 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
@Override @Override
protected void onResume() { protected void onResume() {
if (instanceSyncTask != null) {
instanceSyncTask.setDiskSyncListener(this);
onStartLoading();
}
super.onResume(); super.onResume();
if (instanceSyncTask.getStatus() == AsyncTask.Status.FINISHED) {
// if (instanceSyncTask != null) {
// instanceSyncTask.setDiskSyncListener(this);
// onStartLoading();
// }
if (instanceSyncTask != null && instanceSyncTask.getStatus() == AsyncTask.Status.FINISHED) {
syncComplete(instanceSyncTask.getStatusMessage()); syncComplete(instanceSyncTask.getStatusMessage());
} }
if (deleteInstancesTask != null if (deleteInstancesTask != null && deleteInstancesTask.getStatus() == AsyncTask.Status.FINISHED) {
&& deleteInstancesTask.getStatus() == AsyncTask.Status.FINISHED) {
deleteComplete(deleteInstancesTask.getDeleteCount()); deleteComplete(deleteInstancesTask.getDeleteCount());
} }
if (listDownloadTask != null && listDownloadTask.getStatus() == AsyncTask.Status.FINISHED) {
instanceListDownloadingComplete(listDownloadTask.getDownloadedUri());
}
} }
@Override @Override
...@@ -132,6 +191,10 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -132,6 +191,10 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
deleteInstancesTask.setDeleteListener(null); deleteInstancesTask.setDeleteListener(null);
} }
if (listDownloadTask != null) {
listDownloadTask.setDownloaderListener(null);
}
super.onPause(); super.onPause();
} }
...@@ -171,29 +234,10 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -171,29 +234,10 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
} }
private void refreshItem(boolean init) { private void refreshItem() {
List<InstanceValues> instanceValues = new LinkedList<>(); instanceValueTask = new InstanceValueTask(labels);
instanceValueTask.setInstanceValueListener(this);
String selection = InstanceProviderAPI.InstanceColumns.LATEST + " =? AND " + instanceValueTask.execute();
InstanceProviderAPI.InstanceColumns.JR_FORM_ID + " =?";
String[] selectionArgs = new String[]{InstanceProviderAPI.LATEST_VERSION, formId};
InstancesDao instancesDao = new InstancesDao();
// TODO: 30/06/2018 Sorting order
Cursor data = instancesDao.getInstancesCursor(null, selection, selectionArgs, null);
List<Instance> instanceList = instancesDao.getInstancesFromCursor(data);
for (Instance instance : instanceList) {
File f = new File(instance.getInstanceFilePath());
InstanceValues values = XmlUtils.getInstanceValues(instance.getInstanceUuid(), f, labels);
instanceValues.add(values);
}
if (init) {
tableRowView.initView(instanceValues);
} else {
tableRowView.setRows(instanceValues);
}
} }
@Override @Override
...@@ -212,7 +256,7 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -212,7 +256,7 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
@Override @Override
public void onEntrySaved() { public void onEntrySaved() {
refreshItem(false); refreshItem();
} }
@Override @Override
...@@ -226,44 +270,38 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -226,44 +270,38 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
} }
@Override @Override
public void syncComplete(String result) { public void instanceListDownloadingComplete(final Map<String, String> instances) {
onDoneLoading(); if (instances.size() > 0) {
initDataCountView.setText("(" + instances.size() + ")");
FormsDao formsDao = new FormsDao(); downloadButton.setVisibility(View.VISIBLE);
List<Form> forms = formsDao.getFormsFromCursor(formsDao.getFormsCursorForFormId(formId)); downloadButton.setOnClickListener(new View.OnClickListener() {
@Override
File file = new File(forms.get(0).getFormFilePath()); public void onClick(View v) {
List<String> xPaths = XmlUtils.getInstanceXPathList(file); dialog = new ProgressDialog(InstanceActivity.this);
labels = XmlUtils.getFormLabels(formId, file, xPaths); dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setCancelable(false);
tableHeaderView.setColumns(labels);
dialog.setMessage(getString(R.string.please_wait));
refreshItem(true);
dialog.show();
tableRowView.setOnClickListener(new View.OnClickListener() {
@Override downloadTask = new InstanceDownloadTask(formId, instances);
public void onClick(View view) { downloadTask.setDownloaderListener(InstanceActivity.this);
// Toast.makeText(InstanceActivity.this, "Click : " + view.getTag(), Toast.LENGTH_LONG).show(); downloadTask.execute();
}
});
} else {
downloadButton.setVisibility(View.GONE);
}
String instanceUuid = view.getTag().toString(); instanceSyncTask = new InstanceSyncTask();
// entryDialogFragment = FormEntryDialogFragment.newInstance(instanceUuid, instanceSyncTask.setDiskSyncListener(this);
// FormEntryDialogFragment.MODE_EDIT, false); instanceSyncTask.execute();
entryDialogFragment = FormEntryDialogFragment.newInstance(instanceUuid, formId); }
entryDialogFragment.show(getSupportFragmentManager(), instanceUuid);
entryDialogFragment.setOnEntrySavedListener(InstanceActivity.this);
//
// Intent i =new Intent(InstanceActivity.this, ListingFormEntryActivity.class);
// i.putExtra("instanceUuid", view.getTag().toString());
// startActivity(i);
}
});
tableFooterView.setOnTableAddButtonClickListener(new OnTableAddButtonClickListener() { @Override
@Override public void syncComplete(String result) {
public void onAddButtonClick(View v) { refreshItem();
fillBlankForm();
}
});
} }
@Override @Override
...@@ -273,9 +311,9 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -273,9 +311,9 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
private void onStartLoading() { private void onStartLoading() {
progressBarHolder.setVisibility(View.VISIBLE); progressBarHolder.setVisibility(View.VISIBLE);
tableHeaderView.setVisibility(View.GONE); // tableHeaderView.setVisibility(View.INVISIBLE);
tableRowView.setVisibility(View.GONE); tableRowView.setVisibility(View.INVISIBLE);
tableFooterView.setVisibility(View.GONE); tableFooterView.setVisibility(View.INVISIBLE);
} }
private void onErrorLoading(String message) { private void onErrorLoading(String message) {
...@@ -284,8 +322,61 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL ...@@ -284,8 +322,61 @@ public class InstanceActivity extends AppCompatActivity implements OnEntrySavedL
private void onDoneLoading() { private void onDoneLoading() {
progressBarHolder.setVisibility(View.GONE); progressBarHolder.setVisibility(View.GONE);
tableHeaderView.setVisibility(View.VISIBLE); // tableHeaderView.setVisibility(View.VISIBLE);
tableRowView.setVisibility(View.VISIBLE); tableRowView.setVisibility(View.VISIBLE);
tableFooterView.setVisibility(View.VISIBLE); tableFooterView.setVisibility(View.VISIBLE);
} }
@Override
public void onInstanceDownloadProgressUpdate(int progress, int total, String current) {
dialog.setMessage(getString(R.string.fetching_file, current, "" + progress, "" + total));
}
@Override
public void onInstanceDownloadCompleted(HashMap<String, String> result) {
dialog.dismiss();
TreeNode rootTreeNode = TreeNode.root();
Set<String> keySet = result.keySet();
for(String key : keySet) {
String status = result.get(key);
TreeNode childNode;
if(status.equals(InstanceDownloadTask.STATUS_SUCCESS)) {
childNode = new ModeTreeNode(key, "Success", ModeTreeNode.DOWNLOADED);
} else {
childNode = new ModeTreeNode(key, "Failed", ModeTreeNode.FAILED);
}
childNode.setExpanded(true);
childNode.setItemClickEnable(false);
rootTreeNode.addChild(childNode);
}
View treeView = new TreeView(rootTreeNode, this, new NodeViewFactory()).getView();
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Downloads Details")
.setView(treeView)
.setCancelable(false)
.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
instanceSyncTask = new InstanceSyncTask();
instanceSyncTask.setDiskSyncListener(InstanceActivity.this);
instanceSyncTask.execute();
}
})
.create();
dialog.show();
}
@Override
public void onValueParsed(List<InstanceValues> values) {
tableRowView.setRows(values);
onDoneLoading();
}
} }
...@@ -40,26 +40,12 @@ public class HierarchyAdapter extends RecyclerView.Adapter<HierarchyAdapter.View ...@@ -40,26 +40,12 @@ public class HierarchyAdapter extends RecyclerView.Adapter<HierarchyAdapter.View
@NonNull @NonNull
@Override @Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Timber.d("Creating with type %s", viewType);
// BaseHierarchy hierarchy = hierarchies.get(viewType);
// if (hierarchy instanceof PromptHierarchy) {
// ((PromptHierarchy) hierarchy).setOnChangeListener(onChangeListener);
// return new PromptViewHolder(hierarchy.getView());
// } else if (hierarchy instanceof CaptionHierarchy) {
// return new CaptionViewHolder(hierarchy.getView());
// } else {
// // Should not be happening
// return new ViewHolder(hierarchy.getView());
// }
return new ViewHolder(new LinearLayout(parent.getContext())); return new ViewHolder(new LinearLayout(parent.getContext()));
} }
@Override @Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) { public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// if (holder instanceof PromptViewHolder) {
// PromptHierarchy hierarchy = (PromptHierarchy) hierarchies.get(position);
// }
holder.bind(hierarchies.get(position)); holder.bind(hierarchies.get(position));
} }
......
...@@ -60,6 +60,9 @@ public class NodeViewFactory extends BaseNodeViewFactory { ...@@ -60,6 +60,9 @@ public class NodeViewFactory extends BaseNodeViewFactory {
case ModeTreeNode.QUEUED: case ModeTreeNode.QUEUED:
imageStatus.setImageResource(R.drawable.ic_download); imageStatus.setImageResource(R.drawable.ic_download);
break; break;
case ModeTreeNode.FAILED:
imageStatus.setImageResource(R.drawable.ic_cancel);
break;
} }
} else { } else {
secondaryText.setVisibility(View.GONE); secondaryText.setVisibility(View.GONE);
......
...@@ -29,7 +29,7 @@ import id.ac.stis.capi.odk.dto.Form; ...@@ -29,7 +29,7 @@ import id.ac.stis.capi.odk.dto.Form;
public class InstancePreferenceFragment extends BasePreferenceFragment { public class InstancePreferenceFragment extends BasePreferenceFragment {
private PreferencesManager manager; private PreferencesManager manager;
private ListPreference viewModePref, titlePref, constraintPref; private ListPreference viewModePref, titlePref, constraintPref, filterPref;
private MultiSelectListPreference subtitlePref; private MultiSelectListPreference subtitlePref;
private String formId; private String formId;
private FormLabels formLabels; private FormLabels formLabels;
...@@ -53,7 +53,8 @@ public class InstancePreferenceFragment extends BasePreferenceFragment { ...@@ -53,7 +53,8 @@ public class InstancePreferenceFragment extends BasePreferenceFragment {
List<Form> forms = formsDao.getFormsFromCursor(formsDao.getFormsCursorForFormId(formId)); List<Form