Commit 86045cd4 authored by rahadi's avatar rahadi

Added Readme

parent 943b1b12
# ODK Collect
![Platform](https://img.shields.io/badge/platform-Android-blue.svg)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Build status](https://circleci.com/gh/opendatakit/collect.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/opendatakit/collect)
[![Slack status](http://slack.opendatakit.org/badge.svg)](http://slack.opendatakit.org)
# CAPI-STIS
## Belum Implementasi
Sudah ada pada ODK tetapi belum sempat untuk diimplementasikan
CAPI-STIS merupakan aplikasi _Computer Assisted Personal Interviewing (CAPI)_ hasil pengembangan dari ODK Collect yang memiliki tujuan untuk memenuhi kebutuhan dari bisnis proses kegiatan survei yang dilakukan di Badan Pusat Statistik (BPS).
* Merubah pengaturan melalui share QR Code
* Range widget
* Redesign draw activity
* load setting melalui JSON, selain dari collect.settings
## Fitur
Pada *project* ini, CAPI-STIS dikembangkan lebih lanjut untuk mendukung kebutuhan pada kegiatan pemutakhiran. Beberapa fitur utama yang ditawarkan antara lain:
ODK Collect is an Android app for filling out forms. It is designed to be used in resource-constrained environments with challenges such as unreliable connectivity or power infrastructure. ODK Collect is part of Open Data Kit (ODK), a free and open-source set of tools which help organizations author, field, and manage mobile data collection solutions. Learn more about the Open Data Kit project and its history [here](https://opendatakit.org/about/) and read about example ODK deployments [here](https://opendatakit.org/about/deployments/).
- Peningkatan *user interface* pada *summary* isian kuesioner
- Peningkatan *user interface* pada *Form Entry*
- Keterkaitan Kuesioner (*Questionnaire Dependencies*)
ODK Collect renders forms that are compliant with the [ODK XForms standard](http://opendatakit.github.io/xforms-spec/), a subset of the [XForms 1.1 standard](https://www.w3.org/TR/xforms/) with some extensions. The form parsing is done by the [JavaRosa library](https://github.com/opendatakit/javarosa) which Collect includes as a jar.
## Prerequisites
* ODK website: [https://opendatakit.org](https://opendatakit.org)
* ODK Collect usage instructions: [https://opendatakit.org/use/collect](https://opendatakit.org/use/collect/)
* ODK community mailing list: [http://groups.google.com/group/opendatakit](http://groups.google.com/group/opendatakit)
* ODK developer mailing list: [http://groups.google.com/group/opendatakit-developers](http://groups.google.com/group/opendatakit-developers)
* ODK developer Slack chat: [http://slack.opendatakit.org](http://slack.opendatakit.org)
* ODK developer Slack archive: [http://opendatakit.slackarchive.io](http://opendatakit.slackarchive.io)
* ODK developer wiki: [https://github.com/opendatakit/opendatakit/wiki](https://github.com/opendatakit/opendatakit/wiki)
Dalam menggunakan aplikasi ini, terdapat beberapa hal yang harus diperhatikan, antara lain:
## Release cycle
New versions of ODK Collect are released on the last Sunday of each month. We freeze commits to the master branch on the preceding Wednesday (except for bug fixes).
### *Mobile Device*
## Testing a form locally
Spesifikasi minimal dari *device* yang diperlukan untuk menggunakan aplikasi ini adalah sebagai berikut:
1. [Make](https://xlsform.org) or get ([example forms](https://github.com/XLSForm/example-forms), [test forms](https://github.com/XLSForm/test-forms)) an XLSForm.
- **OS:** Android 4.1.x Jelly Bean
- **RAM:** 1GB
- **Storage:** 100MB free space
1. Convert the XLSForm (xlsx) to XForm (xml). Use the [ODK website](http://opendatakit.org/xiframe/) or [XLSForm Offline](https://gumroad.com/l/xlsform-offline) or [pyxform](https://github.com/XLSForm/pyxform).
### *Server*
1. Once you have the XForm, use [adb](https://developer.android.com/studio/command-line/adb.html) to push the form to your device (after [enabling USB debugging](https://www.kingoapp.com/root-tutorials/how-to-enable-usb-debugging-mode-on-android.htm)) or emulator.
```
adb push my_form.xml /sdcard/odk/forms/
```
Aplikasi ini berjalan dengan bergantung pada sebuah *server* dengan **ODK Aggregate** telah terpasang di dalamnya.
1. Launch ODK Collect and tap `Fill Blank Form`. The new form will be there.
Pengembangan CAPI-STIS kali ini hadir bersama dengan pengembangan lebih lanjut dari ODK Aggregate untuk dapat memenuhi kebutuhan yang serupa.
## Setting up your development environment
Aplikasi ODK Aggregate untuk mendukung kegiatan pemutakhiran dapat diakses melalui tautan [ODK Aggregate](https://git.stis.ac.id/lessthink/aggregate).
1. Download and install [Git](https://git-scm.com/downloads) and add it to your PATH
## Development
1. Download and install [Android Studio](https://developer.android.com/studio/index.html)
Secara umum, pengembangan aplikasi lebih lanjut dapat dilakukan dengan langkah-langkah sebagai berikut:
1. Fork the collect project ([why and how to fork](https://help.github.com/articles/fork-a-repo/))
> Note: Langkah-langkah *environtment setup* ini diambil dari README versi asli dari ODK Collect
1. Clone your fork of the project locally. At the command line:
1. Unduh dan install [Git](https://git-scm.com/downloads) pada komputer Anda dan tambahkan ke dalam PATH Anda
git clone https://github.com/YOUR-GITHUB-USERNAME/collect
2. Unduh dan install [Android Studio](https://developer.android.com/studio/index.html)
If you prefer not to use the command line, you can use Android Studio to create a new project from version control using `https://github.com/YOUR-GITHUB-USERNAME/collect`.
3. Fork project ini ke repository Anda ([why and how to fork](https://help.github.com/articles/fork-a-repo/))
1. Open the project in the folder of your clone from Android Studio. To run the project, click on the green arrow at the top of the screen. The emulator is very slow so we generally recommend using a physical device when possible.
4. Clone project yang telah di-fork ke komputer Anda dengan command line berikut:
## Using APIs for local development
git clone <alamat URL dari repository>
To run functionality that makes API calls from your debug-signed builds, you may need to get an API key or otherwise authorize your app.
> Note: Jika Anda lebih memilih untuk tidak menggunakan command line, Anda juga bisa menggunakan Android Studio untuk membuat project baru dari Version Control.
**Google Drive and Sheets APIs** - Follow the instructions in the "Generate the signing certificate fingerprint and register your application" section from [here](https://developers.google.com/drive/android/auth). Enable the Google Drive API [here](https://console.developers.google.com/apis/api/drive/). Enable the Google Sheets API [here](https://console.developers.google.com/apis/api/sheets.googleapis.com).
5. Buka project pada Android Studio. File yang berkaitan dengan project ini dapat ditemukan pada package `id.ac.stis.capi.lessthink`
**Google Maps API** - Follow the instructions [here](https://developers.google.com/maps/documentation/android-api/signup). Please be sure not to commit your personal API key to a branch that you will submit a pull request for.
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.
## Contributing code
Any and all contributions to the project are welcome. ODK Collect is used across the world primarily by organizations with a social purpose so you can have real impact!
## Panduan & Dokumentasi
Issues tagged as [quick win](https://github.com/opendatakit/collect/labels/quick%20win) should be a good place to start. There are also currently many issues tagged as [needs reproduction](https://github.com/opendatakit/collect/labels/needs%20reproduction) which need someone to try to reproduce them with the current version of ODK Collect and comment on the issue with their findings.
Berikut adalah *table of content* dari panduan yang tersedia:
If you're ready to contribute code, see [the contribution guide](CONTRIBUTING.md).
1. Instalasi aplikasi
- Menggunakan APK
- Run project pada Android Studio
2. Penggunaan aplikasi
- Konfigurasi Server
- User Interface pemutakhiran
- Keterkaitan Kuesioner
## Contributing in other ways
If you know a language other than English, consider contributing translations through [Transifex](https://www.transifex.com/opendatakit/odk-collect/).
## Credits
You can also help by improving this documentation.
Banyak pihak yang telah dilibatkan dalam melakukan pengembangan aplikasi ini. Oleh karena itu, pengembang mengucapkan terima kasih kepada:
## Downloading builds
Per-commit debug builds can be found on [CircleCI](https://circleci.com/gh/opendatakit/collect). Login with your GitHub account, click the build you'd like, then find the APK in the Artifacts tab.
Current and previous production builds can be found on the [ODK website](https://opendatakit.org/downloads/download-info/odk-collect-apk).
## Troubleshooting
#### Error when running Robolectric tests from Android Studio on macOS: `build/intermediates/bundles/debug/AndroidManifest.xml (No such file or directory)`
> Configure the default JUnit test runner configuration in order to work around a bug where IntelliJ / Android Studio does not set the working directory to the module being tested. This can be accomplished by editing the run configurations, Defaults -> JUnit and changing the working directory value to $MODULE_DIR$.
> Source: [Robolectric Wiki](https://github.com/robolectric/robolectric/wiki/Running-tests-in-Android-Studio#notes-for-mac).
#### Android Studio Error: `SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.`
When cloning the project from Android Studio, click "No" when prompted to open the `build.gradle` file and then open project.
- Bapak Takdir SST, M.T. (Dosen Pembimbing & Narasumber Seminar)
- Bapak Farid Ridho, M.T. (Dosen Penguji I & Moderator Seminar)
- Bapak Firdaus, MBA (Dosen Penguji II)
- Bapak Yunarso Anang, Ph.D. (Dosen Penguji Validasi)
- Dan pihak lain yang tidak dapat disebutkan satu per satu.
......@@ -207,34 +207,6 @@ public class CapiFormFragment extends Fragment implements FormListDownloaderList
// onDoneLoading();
// }
TreeNode root = TreeNode.root();
for (int i = 0; i < 5; i++) {
TreeNode child = new ModeTreeNode("Child " + i, "child_" + i, ModeTreeNode.DOWNLOADED);
child.setLevel(0);
child.setItemClickEnable(false);
child.setExpanded(true);
root.addChild(child);
for (int j = 0; j < 2; j++) {
TreeNode grandchild = new ModeTreeNode("Grand Child " + j, "grand_child_" + j, ModeTreeNode.QUEUED);
grandchild.setLevel(j + 1);
grandchild.setItemClickEnable(false);
grandchild.setExpanded(true);
child.addChild(grandchild);
}
}
AlertDialog alertDialog = new AlertDialog.Builder(getContext())
.setTitle("VO")
.setView(new TreeView(root, getContext(), new NodeViewFactory()).getView())
.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create();
alertDialog.show();
return v;
}
......
......@@ -17,6 +17,7 @@ import java.util.List;
import id.ac.stis.capi.R;
import id.ac.stis.capi.collectiva.preferences.Constants;
import id.ac.stis.capi.lessthink.fragments.FormEntryDialogFragment;
import id.ac.stis.capi.lessthink.listeners.OnEntrySavedListener;
import id.ac.stis.capi.lessthink.listeners.OnTableAddButtonClickListener;
import id.ac.stis.capi.lessthink.models.FormLabels;
import id.ac.stis.capi.lessthink.models.InstanceValues;
......@@ -33,7 +34,7 @@ import id.ac.stis.capi.odk.provider.InstanceProviderAPI;
import id.ac.stis.capi.odk.utilities.ApplicationConstants;
import timber.log.Timber;
public class ListingInstanceActivity extends AppCompatActivity {
public class ListingInstanceActivity extends AppCompatActivity implements OnEntrySavedListener {
private static final String FORM_ID_KEY = "formid";
private static final String FORMNAME = "formname";
......@@ -42,7 +43,7 @@ public class ListingInstanceActivity extends AppCompatActivity {
private TableRowView tableRowView;
private TableFooterView tableFooterView;
private String formId, formName;
// private FormEntryDialogFragment entryDialogFragment;
private FormLabels labels;
private FormEntryDialogFragment entryDialogFragment;
@Override
......@@ -64,28 +65,11 @@ public class ListingInstanceActivity extends AppCompatActivity {
File file = new File(forms.get(0).getFormFilePath());
List<String> xPaths = XmlUtils.getInstanceXPathList(file);
FormLabels labels = XmlUtils.getFormLabels(formId, file, xPaths);
labels = XmlUtils.getFormLabels(formId, file, xPaths);
tableHeaderView.setColumns(labels);
List<InstanceValues> instanceValues = new LinkedList<>();
String selection = InstanceProviderAPI.InstanceColumns.LATEST + " =? AND " +
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);
}
tableRowView.setRows(instanceValues);
refreshItem(true);
tableRowView.setOnClickListener(new View.OnClickListener() {
@Override
......@@ -98,6 +82,7 @@ public class ListingInstanceActivity extends AppCompatActivity {
entryDialogFragment = FormEntryDialogFragment.newInstance(instanceUuid,
FormEntryDialogFragment.MODE_EDIT, false);
entryDialogFragment.show(getSupportFragmentManager(), instanceUuid);
entryDialogFragment.setOnEntrySavedListener(ListingInstanceActivity.this);
//
// Intent i =new Intent(ListingInstanceActivity.this, ListingFormEntryActivity.class);
// i.putExtra("instanceUuid", view.getTag().toString());
......@@ -113,6 +98,31 @@ public class ListingInstanceActivity extends AppCompatActivity {
});
}
private void refreshItem(boolean init) {
List<InstanceValues> instanceValues = new LinkedList<>();
String selection = InstanceProviderAPI.InstanceColumns.LATEST + " =? AND " +
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
public void onActivityResult(int requestCode, int resultCode, final Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
......@@ -149,4 +159,9 @@ public class ListingInstanceActivity extends AppCompatActivity {
Toast.makeText(this, "Form not exist", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onEntrySaved() {
refreshItem(false);
}
}
......@@ -23,7 +23,9 @@ import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
......@@ -47,9 +49,9 @@ import java.util.Set;
import id.ac.stis.capi.R;
import id.ac.stis.capi.lessthink.adapters.HierarchyAdapter;
import id.ac.stis.capi.lessthink.listeners.OnButtonHierarchyClickListener;
import id.ac.stis.capi.lessthink.listeners.OnAnswerChangedListener;
import id.ac.stis.capi.lessthink.listeners.OnEditRutaSavedListener;
import id.ac.stis.capi.lessthink.listeners.OnButtonHierarchyClickListener;
import id.ac.stis.capi.lessthink.listeners.OnEntrySavedListener;
import id.ac.stis.capi.lessthink.models.BaseHierarchy;
import id.ac.stis.capi.lessthink.models.ButtonHierarchy;
import id.ac.stis.capi.lessthink.models.PromptHierarchy;
......@@ -132,12 +134,13 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
private final Object saveDialogLock = new Object();
private String instanceName;
private Uri instanceUri;
private SaveToDiskTask saveToDiskTask;
private boolean fromDetail;
private int viewMode, locationState;
private String instanceUuid, formPath;
private OnEditRutaSavedListener onEditRutaSavedListener;
private OnEntrySavedListener onEntrySavedListener;
private FormLoaderTask formLoaderTask;
private FormsDao formsDao;
private InstancesDao instancesDao;
......@@ -147,6 +150,9 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
private HierarchyAdapter adapter;
private ArrayList<BaseHierarchy> hierarchies;
private ProgressDialog progressDialog;
private View loadingView;
private ImageView closeButton;
private TextView dialogTitle;
public FormEntryDialogFragment() {
// Required empty public constructor
......@@ -162,13 +168,14 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
return fragment;
}
public void setOnEditRutaSavedListener(OnEditRutaSavedListener onEditRutaSavedListener) {
this.onEditRutaSavedListener = onEditRutaSavedListener;
public void setOnEntrySavedListener(OnEntrySavedListener onEntrySavedListener) {
this.onEntrySavedListener = onEntrySavedListener;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
instanceUuid = getArguments().getString(INSTANCE_UUID);
fromDetail = getArguments().getBoolean(FLAG_FROM_DETAIL);
......@@ -189,6 +196,8 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
instanceUri = ContentUris.withAppendedId(InstanceProviderAPI.InstanceColumns.CONTENT_URI,
instance.getIdInstance());
instanceName = instance.getDisplayName();
formsDao = new FormsDao();
Cursor c1 = formsDao.getFormsCursorForFormId(formId);
......@@ -226,6 +235,11 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
View v = inflater.inflate(R.layout.fragment_updating_dialog, null);
// questionContainer = v.findViewById(R.id.question_container);
mainContent = v.findViewById(R.id.question_container);
loadingView = v.findViewById(R.id.loading_view);
closeButton = v.findViewById(R.id.close_button);
dialogTitle = v.findViewById(R.id.dialog_title);
dialogTitle.setText(instanceName);
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
mainContent.setLayoutManager(layoutManager);
......@@ -238,11 +252,14 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
builder.setView(v).setPositiveButton(getString(R.string.save_all_answers), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if (null != onEditRutaSavedListener) {
onEditRutaSavedListener.onEditRutaSaved();
saveDataToDisk();
}
});
saveDataToDisk();
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
......@@ -403,6 +420,8 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
@Override
public void loadingComplete(FormLoaderTask task) {
loadingView.setVisibility(View.GONE);
final FormController formController = task.getFormController();
int requestCode = task.getRequestCode(); // these are bogus if
// pendingActivityResult is
......@@ -1148,6 +1167,10 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
public void savingComplete(SaveResult saveStatus) {
dismissProgressDialog();
dismiss();
if (null != onEntrySavedListener) {
onEntrySavedListener.onEntrySaved();
}
}
}
......@@ -5,7 +5,7 @@ package id.ac.stis.capi.lessthink.listeners;
* Email : 14.8325@stis.ac.id
* Company: Politeknik Statistika STIS
*/
public interface OnEditRutaSavedListener {
void onEditRutaSaved();
public interface OnEntrySavedListener {
void onEntrySaved();
}
......@@ -112,7 +112,7 @@ public class TableRowView extends HorizontalScrollView implements OnHandlerMoved
return currentPage;
}
public void setRows(List<InstanceValues> rows) {
public void initView(List<InstanceValues> rows) {
this.rows = rows;
this.currentPage = 1;
......@@ -190,6 +190,11 @@ public class TableRowView extends HorizontalScrollView implements OnHandlerMoved
requestLayout();
}
public void setRows(List<InstanceValues> rows) {
this.rows = rows;
addRowChildren(1);
}
private void addRowChildren(int page) {
row.removeAllViews();
......
......@@ -74,7 +74,6 @@ import timber.log.Timber;
* @author mitchellsundt@gmail.com
*/
public final class WebUtils {
public static final String OPEN_ROSA_VERSION_HEADER = "X-OpenRosa-Version";
public static final String OPEN_ROSA_VERSION = "1.0";
public static final String HTTP_CONTENT_TYPE_TEXT_XML = "text/xml";
......
......@@ -5,6 +5,45 @@
android:layout_height="match_parent"
android:background="@android:color/white">
<android.support.constraint.ConstraintLayout
android:id="@+id/loading_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/dialog_header">
<ProgressBar
android:id="@+id/progressBar2"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@string/please_wait"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar2" />
</android.support.constraint.ConstraintLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/question_container"
android:layout_width="match_parent"
......@@ -24,7 +63,7 @@
android:focusableInTouchMode="true">
<ImageButton
android:id="@+id/close_button"
android:id="@+id/back_button"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="50dp"
android:layout_height="wrap_content"
......@@ -32,6 +71,7 @@
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:tint="@android:color/white"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
......@@ -48,14 +88,14 @@
android:textColor="@android:color/white"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/edit_button"
app:layout_constraintEnd_toStartOf="@+id/edit_button"
app:layout_constraintBottom_toBottomOf="@+id/close_button"
app:layout_constraintEnd_toStartOf="@+id/close_button"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toEndOf="@+id/close_button"
app:layout_constraintTop_toTopOf="@+id/edit_button" />
app:layout_constraintStart_toEndOf="@+id/back_button"
app:layout_constraintTop_toTopOf="@+id/close_button" />
<ImageButton
android:id="@+id/edit_button"
android:id="@+id/close_button"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="50dp"
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