diff --git a/app/Utils.java b/app/Utils.java new file mode 100644 index 0000000..939a624 --- /dev/null +++ b/app/Utils.java @@ -0,0 +1,43 @@ +package com.example.simplefootexam.utils; + +import android.content.Context; +import androidx.annotation.RawRes; +import com.example.simplefootexam.R; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import java.io.InputStream; +import java.util.Scanner; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; + +public class Utils { + + @HunterDebug + public String readRawResource(@RawRes int res, Context context) { + return readStream(context.getResources().openRawResource(res)); + } + + @HunterDebug + private static String readStream(InputStream is) { + Scanner s = new Scanner(is).useDelimiter("\\A"); + return s.hasNext() ? s.next() : ""; + } + + @HunterDebug + public static JSONArray loadSONFile(Context ctx) { + String filecontent = null; + JSONArray jo = new JSONArray(); + try { + filecontent = readStream(ctx.getResources().openRawResource(R.raw.questions)); + } catch (Exception e) { + e.printStackTrace(); + } + try { + return new JSONArray(filecontent); + } catch (JSONException e) { + e.printStackTrace(); + } + return jo; + } +} diff --git a/app/build.gradle b/app/build.gradle index 920bcd3..72b27c7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,19 +1,27 @@ plugins { id 'com.android.application' + id 'hunter-debug' } android { + lintOptions { + abortOnError false + } + dexOptions { + preDexLibraries false + javaMaxHeapSize "8g" + } compileSdkVersion 30 buildToolsVersion "30.0.0" defaultConfig { applicationId "com.example.simplefootexam" minSdkVersion 27 - targetSdkVersion 30 + targetSdkVersion 28 versionCode 1 versionName "1.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } buildTypes { @@ -44,4 +52,7 @@ dependencies { testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' -} \ No newline at end of file +} +dependencies{ + implementation 'io.github.greensoftwarelab:hunter-emanafa-library:1.0.1' + } diff --git a/app/src/main/java/com/example/simplefootexam/CustomButton.java b/app/src/main/java/com/example/simplefootexam/CustomButton.java index 9b20c7d..037597f 100644 --- a/app/src/main/java/com/example/simplefootexam/CustomButton.java +++ b/app/src/main/java/com/example/simplefootexam/CustomButton.java @@ -6,34 +6,36 @@ import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; - import androidx.appcompat.widget.AppCompatButton; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; public class CustomButton extends AppCompatButton { - private boolean isWrong =false; + private boolean isWrong = false; + private int color_wrong; public CustomButton(Context context) { super(context); } + @HunterDebug public CustomButton(Context context, AttributeSet attrs) { super(context, attrs); - TypedArray a = context.obtainStyledAttributes(attrs, - R.styleable.CustomButton, 0, 0); - color_wrong = a.getColor(R.styleable.CustomButton_valueColor, - Color.RED); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomButton, 0, 0); + color_wrong = a.getColor(R.styleable.CustomButton_valueColor, Color.RED); } @Override + @HunterDebug protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if(isWrong) { + if (isWrong) { Paint p = new Paint(); p.setColor(color_wrong); p.setStrokeWidth(10); - canvas.drawLine(0,this.getY(), this.getWidth(), this.getHeight(), p); + canvas.drawLine(0, this.getY(), this.getWidth(), this.getHeight(), p); canvas.drawLine(0, this.getHeight(), this.getWidth(), this.getY(), p); } } @@ -41,4 +43,4 @@ protected void onDraw(Canvas canvas) { public void setWrong(boolean wrong) { isWrong = wrong; } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/simplefootexam/MainActivity.java b/app/src/main/java/com/example/simplefootexam/MainActivity.java index de210d1..437d2ad 100644 --- a/app/src/main/java/com/example/simplefootexam/MainActivity.java +++ b/app/src/main/java/com/example/simplefootexam/MainActivity.java @@ -1,13 +1,17 @@ package com.example.simplefootexam; + import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; public class MainActivity extends AppCompatActivity { @Override + @HunterDebug protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); @@ -16,22 +20,18 @@ protected void onCreate(Bundle savedInstanceState) { } @Override + @HunterDebug public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/simplefootexam/MainMenuFragment.java b/app/src/main/java/com/example/simplefootexam/MainMenuFragment.java index bf7351d..7ac2a55 100644 --- a/app/src/main/java/com/example/simplefootexam/MainMenuFragment.java +++ b/app/src/main/java/com/example/simplefootexam/MainMenuFragment.java @@ -4,29 +4,29 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; public class MainMenuFragment extends Fragment { @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState - ) { + @HunterDebug + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_first, container, false); } + @HunterDebug public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View view) { - NavHostFragment.findNavController(MainMenuFragment.this) - .navigate(R.id.action_FirstFragment_to_QuestionFragment); + NavHostFragment.findNavController(MainMenuFragment.this).navigate(R.id.action_FirstFragment_to_QuestionFragment); } }); } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/simplefootexam/QuestionCardRecyclerViewAdapter.java b/app/src/main/java/com/example/simplefootexam/QuestionCardRecyclerViewAdapter.java index 173cb50..2e3a41d 100644 --- a/app/src/main/java/com/example/simplefootexam/QuestionCardRecyclerViewAdapter.java +++ b/app/src/main/java/com/example/simplefootexam/QuestionCardRecyclerViewAdapter.java @@ -11,11 +11,9 @@ import android.widget.TextView; import com.example.simplefootexam.model.Question; import java.util.List; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; - -/** - * {@link RecyclerView.Adapter} that can display a {@link Question}. - */ public class QuestionCardRecyclerViewAdapter extends RecyclerView.Adapter { private final List mValues; @@ -25,18 +23,19 @@ public QuestionCardRecyclerViewAdapter(List items) { } @Override + @HunterDebug public QuestionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.fragment_question_item, parent, false); + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_question_item, parent, false); return new QuestionViewHolder(v); } @Override + @HunterDebug public void onBindViewHolder(final QuestionViewHolder holder, int position) { holder.mIdView.setText(mValues.get(position).getId()); - holder.mImageView.setImageBitmap( BitmapFactory.decodeResource(holder.mView.getResources(), mValues.get(position).getImageId())); + holder.mImageView.setImageBitmap(BitmapFactory.decodeResource(holder.mView.getResources(), mValues.get(position).getImageId())); holder.mQuestionview.setText(mValues.get(position).getQuestion()); - holder.mView.setOnClickListener(view -> { + holder.mView.setOnClickListener( view -> { Bundle bundle = new Bundle(); bundle.putParcelable("question", mValues.get(position)); Navigation.findNavController(view).navigate(R.id.selectQuestionAction, bundle); @@ -48,19 +47,22 @@ public int getItemCount() { return mValues.size(); } - public static class QuestionViewHolder extends RecyclerView.ViewHolder{ + public static class QuestionViewHolder extends RecyclerView.ViewHolder { + public final View mView; + public final TextView mIdView; + public final TextView mQuestionview; + public final ImageView mImageView; public QuestionViewHolder(View view) { super(view); mView = view; - mIdView = view.findViewById(R.id.text_question_id); + mIdView = view.findViewById(R.id.text_question_id); mImageView = view.findViewById(R.id.cardimage); mQuestionview = view.findViewById(R.id.text_question); - } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/simplefootexam/QuestionListFragment.java b/app/src/main/java/com/example/simplefootexam/QuestionListFragment.java index 2aa7900..1220348 100644 --- a/app/src/main/java/com/example/simplefootexam/QuestionListFragment.java +++ b/app/src/main/java/com/example/simplefootexam/QuestionListFragment.java @@ -3,36 +3,30 @@ import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; - import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; - import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; - import com.example.simplefootexam.viewmodel.QuestionViewModel; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; - -/** - * A fragment representing a list of Items. - */ public class QuestionListFragment extends Fragment { private static final String ARG_COLUMN_COUNT = "column-count"; + private int mColumnCount = 1; + private QuestionViewModel questionViewModel; - /** - * Mandatory empty constructor for the fragment manager to instantiate the - * fragment (e.g. upon screen orientation changes). - */ public QuestionListFragment() { } + @HunterDebug public static QuestionListFragment newInstance(int columnCount) { QuestionListFragment fragment = new QuestionListFragment(); Bundle args = new Bundle(); @@ -42,18 +36,19 @@ public static QuestionListFragment newInstance(int columnCount) { } @Override + @HunterDebug public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT); } ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(this.getActivity().getApplication()); - questionViewModel = new ViewModelProvider(this, factory).get(QuestionViewModel.class); + questionViewModel = new ViewModelProvider(this, factory).get(QuestionViewModel.class); } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + @HunterDebug + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_question_list, container, false); if (view instanceof RecyclerView) { Context context = view.getContext(); @@ -70,8 +65,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, } @Override + @HunterDebug public void onResume() { super.onResume(); } - -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/simplefootexam/SingleQuestionFragment.java b/app/src/main/java/com/example/simplefootexam/SingleQuestionFragment.java index 96e2c2e..8ad90dc 100644 --- a/app/src/main/java/com/example/simplefootexam/SingleQuestionFragment.java +++ b/app/src/main/java/com/example/simplefootexam/SingleQuestionFragment.java @@ -1,4 +1,5 @@ package com.example.simplefootexam; + import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.LayoutInflater; @@ -7,65 +8,71 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import com.example.simplefootexam.model.Question; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; - import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; public class SingleQuestionFragment extends Fragment { @BindView(R.id.textViewQuestion) TextView textViewQuestion; + @BindView(R.id.imageQuestion) ImageView questionImage; + @BindView(R.id.button_top_left) CustomButton buttonTopLeft; + @BindView(R.id.button_top_right) CustomButton buttonTopRight; + @BindView(R.id.button_bottom_left) CustomButton buttonBottomLeft; + @BindView(R.id.button_bottom_right) CustomButton buttonBottomRight; + Question question; @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + @HunterDebug + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_single_question, container, false); ButterKnife.bind(this, v); return v; } - @OnClick({R.id.button_top_left, R.id.button_top_right, R.id.button_bottom_left, R.id.button_bottom_right}) + @OnClick({ R.id.button_top_left, R.id.button_top_right, R.id.button_bottom_left, R.id.button_bottom_right }) + @HunterDebug public void onClickOnButtons(View view) { - if (view instanceof CustomButton){ + if (view instanceof CustomButton) { String txt = ((CustomButton) view).getText().toString(); - if(txt.equals(question.getAnswer())){ + if (txt.equals(question.getAnswer())) { Toast.makeText(getContext(), "Your answer is correct", Toast.LENGTH_LONG).show(); - } - else{ + } else { ((CustomButton) view).setWrong(true); view.invalidate(); } - } + } } + @HunterDebug public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Question q = getArguments().getParcelable("question"); setQuestion(q); } + @HunterDebug public void setQuestion(Question quest) { question = quest; List l = new ArrayList<>(Arrays.asList(question.alternatives)); @@ -75,7 +82,6 @@ public void setQuestion(Question quest) { buttonBottomLeft.setText(l.get(2)); buttonBottomRight.setText(l.get(3)); textViewQuestion.setText(question.getQuestion()); - questionImage.setImageBitmap( BitmapFactory.decodeResource(this.getResources(), quest.getImageId())); - + questionImage.setImageBitmap(BitmapFactory.decodeResource(this.getResources(), quest.getImageId())); } } diff --git a/app/src/main/java/com/example/simplefootexam/model/Question.java b/app/src/main/java/com/example/simplefootexam/model/Question.java index bea391d..8504482 100644 --- a/app/src/main/java/com/example/simplefootexam/model/Question.java +++ b/app/src/main/java/com/example/simplefootexam/model/Question.java @@ -2,25 +2,32 @@ import android.os.Parcel; import android.os.Parcelable; - import com.example.simplefootexam.R; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; public class Question implements Parcelable { + private final String id; + private final String question; + private final int imageId; + public String[] alternatives; + @HunterDebug public Question(String id, int image_id) { this.id = id; this.imageId = image_id; this.question = "?"; this.alternatives = new String[4]; } + + @HunterDebug public Question(String id, String question, int image_id, String answer) { this.id = id; this.imageId = image_id; @@ -28,6 +35,7 @@ public Question(String id, String question, int image_id, String answer) { this.alternatives = new String[4]; } + @HunterDebug protected Question(Parcel in) { id = in.readString(); question = in.readString(); @@ -35,74 +43,87 @@ protected Question(Parcel in) { in.readStringArray(alternatives); } - + @HunterDebug public Question(int id, JSONObject jo) throws JSONException, NoSuchFieldException, IllegalAccessException { this.id = String.valueOf(id); this.question = jo.getString("question"); - this.imageId = R.drawable.class.getField(jo.getString("image")).getInt(null); ; + this.imageId = R.drawable.class.getField(jo.getString("image")).getInt(null); + ; JSONArray alts = jo.getJSONArray("alternatives"); - this.alternatives = new String[4]; + this.alternatives = new String[4]; for (int i = 0; i < alts.length() && i < 4; i++) { this.alternatives[i] = alts.get(i).toString(); } } + @HunterDebug public String getId() { return id; } + @HunterDebug public String getQuestion() { return question; } + @HunterDebug public int getImageId() { return imageId; } + @HunterDebug public String[] getAlternatives() { return alternatives; } + @HunterDebug public void setAlternatives(String[] alternatives) { this.alternatives = alternatives; } + @HunterDebug public static Creator getCREATOR() { return CREATOR; } - public String getAnswer(){ + @HunterDebug + public String getAnswer() { return this.alternatives.length > 0 ? this.alternatives[0] : null; } - public static final Creator CREATOR = new Creator() { + @Override + @HunterDebug public Question createFromParcel(Parcel in) { return new Question(in); } @Override + @HunterDebug public Question[] newArray(int size) { return new Question[size]; } }; @Override + @HunterDebug public String toString() { return question + id; } @Override + @HunterDebug public int describeContents() { return 0; } @Override + @HunterDebug public void writeToParcel(Parcel parcel, int i) { parcel.writeString(id); parcel.writeString(question); - parcel.writeInt (imageId); + parcel.writeInt(imageId); parcel.writeStringArray(alternatives); } } diff --git a/app/src/main/java/com/example/simplefootexam/utils/Utils.java b/app/src/main/java/com/example/simplefootexam/utils/Utils.java index b959182..939a624 100644 --- a/app/src/main/java/com/example/simplefootexam/utils/Utils.java +++ b/app/src/main/java/com/example/simplefootexam/utils/Utils.java @@ -1,30 +1,31 @@ package com.example.simplefootexam.utils; import android.content.Context; - import androidx.annotation.RawRes; - import com.example.simplefootexam.R; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; - import java.io.InputStream; import java.util.Scanner; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; public class Utils { + @HunterDebug public String readRawResource(@RawRes int res, Context context) { return readStream(context.getResources().openRawResource(res)); } + @HunterDebug private static String readStream(InputStream is) { Scanner s = new Scanner(is).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; } - public static JSONArray loadSONFile(Context ctx){ + @HunterDebug + public static JSONArray loadSONFile(Context ctx) { String filecontent = null; JSONArray jo = new JSONArray(); try { diff --git a/app/src/main/java/com/example/simplefootexam/viewmodel/QuestionViewModel.java b/app/src/main/java/com/example/simplefootexam/viewmodel/QuestionViewModel.java index ef79603..ae71c35 100644 --- a/app/src/main/java/com/example/simplefootexam/viewmodel/QuestionViewModel.java +++ b/app/src/main/java/com/example/simplefootexam/viewmodel/QuestionViewModel.java @@ -3,14 +3,10 @@ import android.app.Application; import android.content.Context; import android.os.AsyncTask; - import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; - import com.example.simplefootexam.model.Question; import com.example.simplefootexam.utils.Utils; - - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -18,19 +14,24 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.hunter.library.debug.HunterDebug; +import android.content.Context; public class QuestionViewModel extends AndroidViewModel { - private static Map questions = new HashMap<>(); + private static Map questions = new HashMap<>(); + private static boolean isLoaded = false; + @HunterDebug public QuestionViewModel(@NonNull Application application) { super(application); initQuestions(application.getApplicationContext()); } - private static void initQuestions(Context ctx){ - if(isLoaded){ + @HunterDebug + private void initQuestions(Context ctx) { + if (isLoaded) { return; } JSONArray jsonArray = Utils.loadSONFile(ctx); @@ -47,9 +48,8 @@ private static void initQuestions(Context ctx){ isLoaded = true; } - public List getQuestions(){ + @HunterDebug + public List getQuestions() { return new ArrayList<>(questions.values()); } - - } diff --git a/build.gradle b/build.gradle index 4d24be2..1e7cd35 100644 --- a/build.gradle +++ b/build.gradle @@ -21,4 +21,12 @@ allprojects { task clean(type: Delete) { delete rootProject.buildDir -} \ No newline at end of file +} +buildscript{ + dependencies{ +classpath 'io.github.raphael28:hunter-debug-plugin:1.0.1' +classpath 'io.github.raphael28:hunter-transform:0.9.8' + +} +} +allprojects {repositories {flatDir { dirs 'libs'}}} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..52f5917 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,19 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true \ No newline at end of file