From d3611bd7b7661d687972ddfb4a61dbd9128a4ece Mon Sep 17 00:00:00 2001 From: fpeterfalvi <fpeterfalvi@gmail.com> Date: Thu, 26 Apr 2018 21:37:15 +0200 Subject: [PATCH] In normal game server user can set time limit for answering. --- .../kvizclient/AnsweredQuestionFragment.java | 11 +++-- .../java/onlab/kvizclient/GameActivity.java | 23 ++++------ .../kvizclient/GuessQuestionFragment.java | 24 ++++++++-- .../onlab/kvizclient/MessageFragment.java | 2 +- .../kvizclient/MultipleChoiceFragment.java | 25 ++++++++-- .../java/onlab/kvizclient/QuizUpActivity.java | 8 ++-- KvizServer/app/src/main/AndroidManifest.xml | 10 ++-- .../java/onlab/kvizserver/GameActivity.java | 46 ++++++------------- .../onlab/kvizserver/GameControlFragment.java | 30 +++++++++++- .../onlab/kvizserver/QuestionListAdapter.java | 4 +- .../main/res/layout/fragment_game_control.xml | 30 +++++++++++- .../main/res/layout/item_question_list.xml | 2 +- 12 files changed, 145 insertions(+), 70 deletions(-) diff --git a/KvizClient/app/src/main/java/onlab/kvizclient/AnsweredQuestionFragment.java b/KvizClient/app/src/main/java/onlab/kvizclient/AnsweredQuestionFragment.java index 37cf1f2..028172e 100644 --- a/KvizClient/app/src/main/java/onlab/kvizclient/AnsweredQuestionFragment.java +++ b/KvizClient/app/src/main/java/onlab/kvizclient/AnsweredQuestionFragment.java @@ -1,10 +1,10 @@ package onlab.kvizclient; -import android.app.Fragment; import android.graphics.Color; import android.graphics.Typeface; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; @@ -80,8 +80,13 @@ public class AnsweredQuestionFragment extends Fragment { TextView correctAnswerTextView = (TextView) getView().findViewById(R.id.AQFCorrectAnswerTextView); correctAnswerTextView.setText("Correct answer: " + Integer.toString(correct_answer)); TextView ownAnswerTextView = (TextView) getView().findViewById(R.id.OwnAnswerTextView); - ownAnswerTextView.setText("Your answer: " + Integer.toString(playerAnswers.get(own_index).getValue()) - + " (" + Double.toString(playerAnswers.get(own_index).getTime()) + "s)"); + int answerInt = playerAnswers.get(own_index).getValue(); + if (answerInt != -2) { + ownAnswerTextView.setText("Your answer: " + Integer.toString(answerInt) + + " (" + Double.toString(playerAnswers.get(own_index).getTime()) + "s)"); + } else { + ownAnswerTextView.setText("Your answer: nem válaszolt"); + } if (playerAnswers.get(own_index).isWinner()) { ownAnswerTextView.setTextColor(Color.GREEN); ownAnswerTextView.setTextColor(Color.rgb(31, 114, 70)); diff --git a/KvizClient/app/src/main/java/onlab/kvizclient/GameActivity.java b/KvizClient/app/src/main/java/onlab/kvizclient/GameActivity.java index e652827..8273760 100644 --- a/KvizClient/app/src/main/java/onlab/kvizclient/GameActivity.java +++ b/KvizClient/app/src/main/java/onlab/kvizclient/GameActivity.java @@ -1,27 +1,20 @@ package onlab.kvizclient; -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; import android.os.Handler; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; import android.widget.TextView; -import org.w3c.dom.Text; - import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; -import java.net.UnknownHostException; -import java.util.Calendar; import java.util.Date; public class GameActivity extends AppCompatActivity implements MultipleChoiceFragment.OnFragmentInteractionListener, @@ -102,7 +95,7 @@ public class GameActivity extends AppCompatActivity implements MultipleChoiceFra } private void replaceFragment(String[] strings) { - FragmentManager fm = getFragmentManager(); + FragmentManager fm = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fm.beginTransaction(); if (strings[0].equals("questionMC") || strings[0].equals("questionG")) { questionReceivedDate = new Date(); @@ -111,7 +104,7 @@ public class GameActivity extends AppCompatActivity implements MultipleChoiceFra if (strings[0].equals("questionMC") || strings[0].equals("answerMC")) { frag = MultipleChoiceFragment.newInstance( strings[1], strings[2], strings[3], strings[4], strings[5], - strings[6], Integer.parseInt(strings[7]), Integer.parseInt(strings[8]), -1); + strings[6], Integer.parseInt(strings[7]), Integer.parseInt(strings[8]), Integer.parseInt(strings[9])); } else if (strings[0].equals("questionG")) { frag = GuessQuestionFragment.newInstance(strings[1], Integer.parseInt(strings[2])); } else if (strings[0].equals("answerG")) { @@ -129,7 +122,11 @@ public class GameActivity extends AppCompatActivity implements MultipleChoiceFra Date questionAnsweredDate = new Date(); double answerTime = (double)(questionAnsweredDate.getTime() - questionReceivedDate.getTime()) / 1000; Log.d("A válasz: ", Integer.toString(answer) + " (" + Double.toString(answerTime) + "s)"); - displayTextView.setText(answer + " (" + Double.toString(answerTime) + "s)"); + if (answer != -2) { + displayTextView.setText(answer + " (" + Double.toString(answerTime) + "s)"); + } else { + displayTextView.setText("nem válaszolt"); + } output.println(Integer.toString(answer) + "##" + Double.toString(answerTime)); } diff --git a/KvizClient/app/src/main/java/onlab/kvizclient/GuessQuestionFragment.java b/KvizClient/app/src/main/java/onlab/kvizclient/GuessQuestionFragment.java index 7a31280..582f25d 100644 --- a/KvizClient/app/src/main/java/onlab/kvizclient/GuessQuestionFragment.java +++ b/KvizClient/app/src/main/java/onlab/kvizclient/GuessQuestionFragment.java @@ -1,9 +1,11 @@ package onlab.kvizclient; import android.app.Activity; -import android.app.Fragment; +import android.content.Context; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -36,6 +38,8 @@ public class GuessQuestionFragment extends Fragment { private ProgressBar progressBar; + private Handler updateConversationHandler; + public GuessQuestionFragment() { // Required empty public constructor } @@ -56,6 +60,7 @@ public class GuessQuestionFragment extends Fragment { question = getArguments().getString(QUESTION); timeout = getArguments().getInt(TIMEOUT); } + updateConversationHandler = new Handler(); } @Override @@ -137,7 +142,7 @@ public class GuessQuestionFragment extends Fragment { } @Override - public void onAttach(Activity context) { + public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; @@ -198,10 +203,23 @@ public class GuessQuestionFragment extends Fragment { answered = true; progressBar.setProgress(0); if (mListener != null) { - mListener.onAnswered(-2); + updateConversationHandler.post(new GuessQuestionFragment.updateUIThread(-2)); Log.d("FRAGMENT", "Letelt az idő"); } } } } + + class updateUIThread implements Runnable { + int answer; + + public updateUIThread(int answer) { + this.answer = answer; + } + + @Override + public void run() { + mListener.onAnswered(answer); + } + } } diff --git a/KvizClient/app/src/main/java/onlab/kvizclient/MessageFragment.java b/KvizClient/app/src/main/java/onlab/kvizclient/MessageFragment.java index 1d1aee1..ff3d688 100644 --- a/KvizClient/app/src/main/java/onlab/kvizclient/MessageFragment.java +++ b/KvizClient/app/src/main/java/onlab/kvizclient/MessageFragment.java @@ -3,7 +3,7 @@ package onlab.kvizclient; import android.os.Bundle; import android.support.annotation.Nullable; -import android.app.Fragment; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/KvizClient/app/src/main/java/onlab/kvizclient/MultipleChoiceFragment.java b/KvizClient/app/src/main/java/onlab/kvizclient/MultipleChoiceFragment.java index aee66e7..ed230c6 100644 --- a/KvizClient/app/src/main/java/onlab/kvizclient/MultipleChoiceFragment.java +++ b/KvizClient/app/src/main/java/onlab/kvizclient/MultipleChoiceFragment.java @@ -1,10 +1,12 @@ package onlab.kvizclient; import android.app.Activity; -import android.app.Fragment; +import android.content.Context; import android.graphics.Color; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; @@ -56,6 +58,8 @@ public class MultipleChoiceFragment extends Fragment { private ProgressBar progressBar; + private Handler updateConversationHandler; + public MultipleChoiceFragment() { // Required empty public constructor } @@ -94,6 +98,7 @@ public class MultipleChoiceFragment extends Fragment { own_index = getArguments().getInt(OWN_INDEX); correct_answer = getArguments().getInt(CORRECT_ANSWER); timeout = getArguments().getInt(TIMEOUT); + updateConversationHandler = new Handler(); } } @@ -187,7 +192,7 @@ public class MultipleChoiceFragment extends Fragment { } @Override - public void onAttach(Activity context) { + public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; @@ -251,10 +256,24 @@ public class MultipleChoiceFragment extends Fragment { answered = true; progressBar.setProgress(0); if (mListener != null) { - mListener.onAnswered(-2); + updateConversationHandler.post(new MultipleChoiceFragment.updateUIThread(-2)); Log.d("FRAGMENT", "Letelt az idő"); } } } } + + class updateUIThread implements Runnable { + int answer; + + public updateUIThread(int answer) { + this.answer = answer; + } + + @Override + public void run() { + mListener.onAnswered(answer); + } + } + } diff --git a/KvizClient/app/src/main/java/onlab/kvizclient/QuizUpActivity.java b/KvizClient/app/src/main/java/onlab/kvizclient/QuizUpActivity.java index bad5c35..9a65e1e 100644 --- a/KvizClient/app/src/main/java/onlab/kvizclient/QuizUpActivity.java +++ b/KvizClient/app/src/main/java/onlab/kvizclient/QuizUpActivity.java @@ -1,9 +1,9 @@ package onlab.kvizclient; -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; import android.os.Handler; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; @@ -103,7 +103,7 @@ public class QuizUpActivity extends AppCompatActivity implements MultipleChoiceF } private void replaceFragment(String[] strings) { - FragmentManager fm = getFragmentManager(); + FragmentManager fm = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fm.beginTransaction(); Fragment frag; if (strings[0].equals("question")) { diff --git a/KvizServer/app/src/main/AndroidManifest.xml b/KvizServer/app/src/main/AndroidManifest.xml index e94cc85..ef887cb 100644 --- a/KvizServer/app/src/main/AndroidManifest.xml +++ b/KvizServer/app/src/main/AndroidManifest.xml @@ -22,7 +22,7 @@ android:theme="@style/AppTheme"> <activity android:name=".MainActivity" - android:screenOrientation="landscape"> + android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -32,10 +32,12 @@ <activity android:name=".LobbyActivity" android:label="@string/title_activity_lobby" - android:screenOrientation="landscape" + android:screenOrientation="portrait" android:theme="@style/AppTheme.NoActionBar" /> - <activity android:name=".GameActivity" /> - <activity android:name=".QuizUpActivity"> + <activity android:name=".GameActivity" + android:screenOrientation="portrait"/> + <activity android:name=".QuizUpActivity" + android:screenOrientation="portrait"> </activity> </application> diff --git a/KvizServer/app/src/main/java/onlab/kvizserver/GameActivity.java b/KvizServer/app/src/main/java/onlab/kvizserver/GameActivity.java index 3ceb3da..d40f803 100644 --- a/KvizServer/app/src/main/java/onlab/kvizserver/GameActivity.java +++ b/KvizServer/app/src/main/java/onlab/kvizserver/GameActivity.java @@ -7,6 +7,7 @@ import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; +import android.view.WindowManager; import com.google.gson.Gson; @@ -28,8 +29,6 @@ import onlab.kvizserver.model.Question; public class GameActivity extends AppCompatActivity implements GameControlFragment.OnFragmentInteractionListener, QuestionListFragment.OnFragmentInteractionListener { - //private List<Question> questions; - //private int questionIndex = 0; private Question question = null; private int numberOfPlayers; private final List<String> answers = new ArrayList<>(); @@ -51,40 +50,19 @@ public class GameActivity extends AppCompatActivity implements GameControlFragme Bundle extras = getIntent().getExtras(); String questionFileName = extras.getString("QUESTION_FILE_NAME", null); + this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + gson = new Gson(); updateConversationHandler = new Handler(); numberOfPlayers = ClientHolder.size(); - - /* - FragmentManager fm = getSupportFragmentManager(); - FragmentTransaction fragmentTransaction = fm.beginTransaction(); - gameControlFragment = GameControlFragment.newInstance(numberOfPlayers); - fragmentTransaction.replace(R.id.RootLayout, gameControlFragment); - fragmentTransaction.commit(); - */ - gameControlFragment = GameControlFragment.newInstance(numberOfPlayers); questionListFragment = QuestionListFragment.newInstance(questionFileName); ViewPager vpProfile = (ViewPager) findViewById(R.id.GameActivityViewPager); vpProfile.setAdapter(new GameActivityPagerAdapter(getSupportFragmentManager(), gameControlFragment, questionListFragment)); - /* - InputStream inputStream = null; - try { - if (questionFileName == null) { - inputStream = getAssets().open("multiple.txt"); - } else { - inputStream = new FileInputStream(new File(questionFileName)); - } - } catch (IOException e) { - e.printStackTrace(); - } - questions = readQuestions(inputStream); - */ - try { for (int i=0;i<ClientHolder.size();i++) { inputs.add(new BufferedReader(new InputStreamReader(ClientHolder.get(i).getClientsocket().getInputStream()))); @@ -134,9 +112,13 @@ public class GameActivity extends AppCompatActivity implements GameControlFragme int answerInt = Integer.parseInt(strings[0]); playerAnswers[index].setValue(answerInt); playerAnswers[index].setTime(Double.parseDouble(strings[1])); - String answerString = answers.size() == 4 ? answers.get(answerInt) : strings[0]; - updateConversationHandler.post(new GameActivity.updateUIThread(index, - answerString + " (" + strings[1] + "s)")); + String answerString; + if (answers.size() == 4) { + answerString = (answerInt == -2) ? "nem válaszolt" : (answers.get(answerInt) + " (" + strings[1] + "s)"); + } else { + answerString = (answerInt == -2) ? "nem válaszolt" : (strings[0] + " (" + strings[1] + "s)"); + } + updateConversationHandler.post(new GameActivity.updateUIThread(index, answerString)); } } catch (IOException e) { e.printStackTrace(); @@ -195,7 +177,7 @@ public class GameActivity extends AppCompatActivity implements GameControlFragme } @Override - public void nextQuestionButtonClicked() { + public void nextQuestionButtonClicked(int timeLimit) { gameControlFragment.setCorrectAnswerButtonEnabled(true); questionListFragment.selecetedQuestionDisplayed(); gameControlFragment.setNextQuestionButtonEnabled(false); @@ -233,9 +215,9 @@ public class GameActivity extends AppCompatActivity implements GameControlFragme if (question.getType() == Question.MULTIPLE_CHOICE) { outputs.get(i).println("questionMC##" + questionString + "##" + answers.get(0) + "##" + answers.get(1) + "##" + answers.get(2) + "##" + answers.get(3) + "##" + playerAnswersString - + "##" + Integer.toString(i) + "##-1"); + + "##" + Integer.toString(i) + "##-1##" + Integer.toString(timeLimit)); } else { - outputs.get(i).println("questionG##" + questionString + "##-1"); + outputs.get(i).println("questionG##" + questionString + "##" + Integer.toString(timeLimit)); } } @@ -255,7 +237,7 @@ public class GameActivity extends AppCompatActivity implements GameControlFragme String playerAnswersString = gson.toJson(playerAnswers); outputs.get(i).println("answerMC##" + questionString + "##" + answers.get(0) + "##" + answers.get(1) + "##" + answers.get(2) + "##" + answers.get(3) + "##" + playerAnswersString - + "##" + Integer.toString(i) + "##" + Integer.toString(correctAnswer)); + + "##" + Integer.toString(i) + "##" + Integer.toString(correctAnswer) + "##-1"); } else { calculateGuessQuestionWinner(); String playerAnswersString = gson.toJson(playerAnswers); diff --git a/KvizServer/app/src/main/java/onlab/kvizserver/GameControlFragment.java b/KvizServer/app/src/main/java/onlab/kvizserver/GameControlFragment.java index bef3b35..e99026a 100644 --- a/KvizServer/app/src/main/java/onlab/kvizserver/GameControlFragment.java +++ b/KvizServer/app/src/main/java/onlab/kvizserver/GameControlFragment.java @@ -9,8 +9,11 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import java.util.ArrayList; import java.util.List; @@ -29,6 +32,8 @@ public class GameControlFragment extends Fragment { private final List<TextView> answerTextViews = new ArrayList<>(); private Button nextQuestionBtn; private Button correctAnswerButton; + private EditText timeLimitEditText; + private CheckBox timeLimitCheckBox; public GameControlFragment() { // Required empty public constructor @@ -70,6 +75,8 @@ public class GameControlFragment extends Fragment { answerTextViews.add((TextView) getView().findViewById(R.id.Answer4TextView)); correctAnswerTextView = (TextView) getView().findViewById(R.id.CorrectAnswerTextView); final LinearLayout playerAnswersLinearLayout = (LinearLayout) getView().findViewById(R.id.PlayerAnswers); + timeLimitEditText = (EditText) getView().findViewById(R.id.TimeLimitEditText); + timeLimitCheckBox = (CheckBox) getView().findViewById(R.id.TimeLimitCheckBox); for (int i=0;i<numberOfPlayers;i++) { final TextView playerAnswerTextView = new TextView(getActivity()); @@ -88,7 +95,26 @@ public class GameControlFragment extends Fragment { nextQuestionBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - mListener.nextQuestionButtonClicked(); + int timeLimit = -1; + if (timeLimitCheckBox.isChecked()) { + timeLimit = (int) (1000 * Double.parseDouble(timeLimitEditText.getText().toString())); + if (timeLimit <= 0) { + Toast.makeText(getContext(), "Time limit must be positive!", Toast.LENGTH_LONG).show(); + return; + } + } + mListener.nextQuestionButtonClicked(timeLimit); + } + }); + + timeLimitCheckBox.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (timeLimitCheckBox.isChecked()) { + timeLimitEditText.setEnabled(true); + } else { + timeLimitEditText.setEnabled(false); + } } }); } @@ -146,7 +172,7 @@ public class GameControlFragment extends Fragment { public interface OnFragmentInteractionListener { - public void nextQuestionButtonClicked(); + public void nextQuestionButtonClicked(int timeLimit); public void correctAnswerButtonClicked(); diff --git a/KvizServer/app/src/main/java/onlab/kvizserver/QuestionListAdapter.java b/KvizServer/app/src/main/java/onlab/kvizserver/QuestionListAdapter.java index 6f86404..197bedc 100644 --- a/KvizServer/app/src/main/java/onlab/kvizserver/QuestionListAdapter.java +++ b/KvizServer/app/src/main/java/onlab/kvizserver/QuestionListAdapter.java @@ -41,7 +41,7 @@ public class QuestionListAdapter extends RecyclerView.Adapter<QuestionListAdapte @Override public void onBindViewHolder(final QuestionViewHolder holder, final int position) { final Question item = items.get(position); - holder.indexOfQuestionTextView.setText(Integer.toString(position)); + holder.indexOfQuestionTextView.setText(Integer.toString(position + 1)); holder.questionTextTextView.setText(item.getQuestionText()); String answersString = item.getCorrectAnswer(); if (item.getType() == Question.MULTIPLE_CHOICE) { @@ -49,7 +49,7 @@ public class QuestionListAdapter extends RecyclerView.Adapter<QuestionListAdapte answersString += "\n" + otherAnswers.get(0) + "\n" + otherAnswers.get(1) + "\n" + otherAnswers.get(2); } holder.answerTextTextView.setText(answersString); - holder.questionItemMainLayout.setBackgroundColor(Color.LTGRAY); + holder.questionItemMainLayout.setBackgroundColor(Color.WHITE); if (item.isEnabled()) { holder.enableButton.setText("Disable"); } else { diff --git a/KvizServer/app/src/main/res/layout/fragment_game_control.xml b/KvizServer/app/src/main/res/layout/fragment_game_control.xml index e695077..f265c30 100644 --- a/KvizServer/app/src/main/res/layout/fragment_game_control.xml +++ b/KvizServer/app/src/main/res/layout/fragment_game_control.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:padding="20dp" tools:context=".GameControlFragment"> <LinearLayout @@ -70,6 +71,31 @@ android:enabled="false" android:textSize="20sp" /> + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <CheckBox + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:checked="false" + android:id="@+id/TimeLimitCheckBox"/> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Set time limit for answering"/> + + </LinearLayout> + + <EditText + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:enabled="false" + android:hint="Time limit (in s)" + android:id="@+id/TimeLimitEditText" + android:inputType="number"/> + </LinearLayout> -</FrameLayout> \ No newline at end of file +</ScrollView> \ No newline at end of file diff --git a/KvizServer/app/src/main/res/layout/item_question_list.xml b/KvizServer/app/src/main/res/layout/item_question_list.xml index 48a1912..ab2473c 100644 --- a/KvizServer/app/src/main/res/layout/item_question_list.xml +++ b/KvizServer/app/src/main/res/layout/item_question_list.xml @@ -11,7 +11,7 @@ android:layout_height="match_parent" android:id="@+id/IndexOfQuestionTextView" android:textSize="40sp" - android:gravity="center" + android:gravity="center_horizontal" android:layout_margin="10dp" android:text="0"/> -- GitLab