├── LICENSE.txt ├── README.md ├── chapter1-geoquiz ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── geoquiz │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── geoquiz │ │ │ │ ├── domain │ │ │ │ ├── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ └── DataEventListener.java │ │ │ │ └── question │ │ │ │ │ ├── Question.java │ │ │ │ │ ├── QuestionModel.java │ │ │ │ │ ├── QuestionPresenter.java │ │ │ │ │ ├── QuestionView.java │ │ │ │ │ └── StandardQuestionModel.java │ │ │ │ └── platform │ │ │ │ ├── AndroidQuestionView.java │ │ │ │ └── QuizActivity.java │ │ └── res │ │ │ ├── layout │ │ │ └── activity_quiz.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── geoquiz │ │ └── domain │ │ └── question │ │ ├── QuestionPresenterTest.java │ │ └── StandardQuestionModelTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter2-geoquiz-challenges ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── geoquiz │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── geoquiz │ │ │ │ ├── domain │ │ │ │ ├── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ ├── DataEventListener.java │ │ │ │ │ ├── Event.java │ │ │ │ │ └── EventListener.java │ │ │ │ └── question │ │ │ │ │ ├── Question.java │ │ │ │ │ ├── QuestionModel.java │ │ │ │ │ ├── QuestionPresenter.java │ │ │ │ │ ├── QuestionView.java │ │ │ │ │ └── StandardQuestionModel.java │ │ │ │ └── platform │ │ │ │ ├── AndroidQuestionView.java │ │ │ │ └── QuizActivity.java │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-mdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── layout │ │ │ └── activity_quiz.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── geoquiz │ │ └── domain │ │ └── question │ │ ├── QuestionPresenterTest.java │ │ └── StandardQuestionModelTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter2-geoquiz ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── geoquiz │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── geoquiz │ │ │ │ ├── domain │ │ │ │ ├── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ ├── DataEventListener.java │ │ │ │ │ ├── Event.java │ │ │ │ │ └── EventListener.java │ │ │ │ └── question │ │ │ │ │ ├── Question.java │ │ │ │ │ ├── QuestionModel.java │ │ │ │ │ ├── QuestionPresenter.java │ │ │ │ │ ├── QuestionView.java │ │ │ │ │ └── StandardQuestionModel.java │ │ │ │ └── platform │ │ │ │ ├── AndroidQuestionView.java │ │ │ │ └── QuizActivity.java │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-mdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── layout │ │ │ └── activity_quiz.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── geoquiz │ │ └── domain │ │ └── question │ │ ├── QuestionPresenterTest.java │ │ └── StandardQuestionModelTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter3-geoquiz ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── geoquiz │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── geoquiz │ │ │ │ ├── domain │ │ │ │ ├── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ ├── DataEventListener.java │ │ │ │ │ ├── Event.java │ │ │ │ │ └── EventListener.java │ │ │ │ ├── question │ │ │ │ │ ├── Question.java │ │ │ │ │ ├── QuestionModel.java │ │ │ │ │ ├── QuestionPresenter.java │ │ │ │ │ ├── QuestionView.java │ │ │ │ │ └── StandardQuestionModel.java │ │ │ │ └── state │ │ │ │ │ ├── AndroidStateManager.java │ │ │ │ │ ├── StateLoader.java │ │ │ │ │ └── StateSaver.java │ │ │ │ └── platform │ │ │ │ ├── AndroidQuestionView.java │ │ │ │ └── QuizActivity.java │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-mdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── layout-land │ │ │ └── activity_quiz.xml │ │ │ ├── layout │ │ │ └── activity_quiz.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── geoquiz │ │ └── domain │ │ ├── question │ │ ├── QuestionPresenterTest.java │ │ └── StandardQuestionModelTest.java │ │ └── state │ │ └── AndroidStateManagerTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter5-geoquiz-challenges ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── geoquiz │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── geoquiz │ │ │ │ ├── domain │ │ │ │ ├── cheat │ │ │ │ │ ├── CheatModel.java │ │ │ │ │ ├── CheatPresenter.java │ │ │ │ │ ├── CheatView.java │ │ │ │ │ └── StandardCheatModel.java │ │ │ │ ├── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ ├── DataEventListener.java │ │ │ │ │ ├── Event.java │ │ │ │ │ └── EventListener.java │ │ │ │ ├── question │ │ │ │ │ ├── Question.java │ │ │ │ │ ├── QuestionModel.java │ │ │ │ │ ├── QuestionPresenter.java │ │ │ │ │ ├── QuestionView.java │ │ │ │ │ └── StandardQuestionModel.java │ │ │ │ └── state │ │ │ │ │ ├── AndroidStateManager.java │ │ │ │ │ ├── StateLoader.java │ │ │ │ │ └── StateSaver.java │ │ │ │ └── platform │ │ │ │ ├── AndroidCheatView.java │ │ │ │ ├── AndroidQuestionView.java │ │ │ │ ├── CheatActivity.java │ │ │ │ └── QuizActivity.java │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-mdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── layout-land │ │ │ └── activity_quiz.xml │ │ │ ├── layout │ │ │ ├── activity_cheat.xml │ │ │ └── activity_quiz.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-v21 │ │ │ └── styles.xml │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── geoquiz │ │ └── domain │ │ ├── cheat │ │ ├── CheatPresenterTest.java │ │ └── StandardCheatModelTest.java │ │ ├── question │ │ ├── QuestionPresenterTest.java │ │ └── StandardQuestionModelTest.java │ │ └── state │ │ └── AndroidStateManagerTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter5-geoquiz ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── geoquiz │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── geoquiz │ │ │ │ ├── domain │ │ │ │ ├── cheat │ │ │ │ │ ├── CheatModel.java │ │ │ │ │ ├── CheatPresenter.java │ │ │ │ │ ├── CheatView.java │ │ │ │ │ └── StandardCheatModel.java │ │ │ │ ├── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ ├── DataEventListener.java │ │ │ │ │ ├── Event.java │ │ │ │ │ └── EventListener.java │ │ │ │ ├── question │ │ │ │ │ ├── Question.java │ │ │ │ │ ├── QuestionModel.java │ │ │ │ │ ├── QuestionPresenter.java │ │ │ │ │ ├── QuestionView.java │ │ │ │ │ └── StandardQuestionModel.java │ │ │ │ └── state │ │ │ │ │ ├── AndroidStateManager.java │ │ │ │ │ ├── StateLoader.java │ │ │ │ │ └── StateSaver.java │ │ │ │ └── platform │ │ │ │ ├── AndroidCheatView.java │ │ │ │ ├── AndroidQuestionView.java │ │ │ │ ├── CheatActivity.java │ │ │ │ └── QuizActivity.java │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-mdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── layout-land │ │ │ └── activity_quiz.xml │ │ │ ├── layout │ │ │ ├── activity_cheat.xml │ │ │ └── activity_quiz.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-v21 │ │ │ └── styles.xml │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── geoquiz │ │ └── domain │ │ ├── cheat │ │ ├── CheatPresenterTest.java │ │ └── StandardCheatModelTest.java │ │ ├── question │ │ ├── QuestionPresenterTest.java │ │ └── StandardQuestionModelTest.java │ │ └── state │ │ └── AndroidStateManagerTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter6-geoquiz-challenges ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── geoquiz │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── geoquiz │ │ │ │ ├── domain │ │ │ │ ├── cheat │ │ │ │ │ ├── CheatModel.java │ │ │ │ │ ├── CheatPresenter.java │ │ │ │ │ ├── CheatView.java │ │ │ │ │ └── StandardCheatModel.java │ │ │ │ ├── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ ├── DataEventListener.java │ │ │ │ │ ├── Event.java │ │ │ │ │ └── EventListener.java │ │ │ │ ├── question │ │ │ │ │ ├── Question.java │ │ │ │ │ ├── QuestionModel.java │ │ │ │ │ ├── QuestionPresenter.java │ │ │ │ │ ├── QuestionView.java │ │ │ │ │ └── StandardQuestionModel.java │ │ │ │ └── state │ │ │ │ │ ├── AndroidStateManager.java │ │ │ │ │ ├── StateLoader.java │ │ │ │ │ └── StateSaver.java │ │ │ │ └── platform │ │ │ │ ├── AndroidCheatView.java │ │ │ │ ├── AndroidQuestionView.java │ │ │ │ ├── CheatActivity.java │ │ │ │ └── QuizActivity.java │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-mdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── arrow_left.png │ │ │ └── arrow_right.png │ │ │ ├── layout-land │ │ │ └── activity_quiz.xml │ │ │ ├── layout │ │ │ ├── activity_cheat.xml │ │ │ └── activity_quiz.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-v21 │ │ │ └── styles.xml │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── geoquiz │ │ └── domain │ │ ├── cheat │ │ ├── CheatPresenterTest.java │ │ └── StandardCheatModelTest.java │ │ ├── question │ │ ├── QuestionPresenterTest.java │ │ └── StandardQuestionModelTest.java │ │ └── state │ │ └── AndroidStateManagerTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter7-criminalintent ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── criminalintent │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── criminalintent │ │ │ │ ├── domain │ │ │ │ ├── crime │ │ │ │ │ ├── Crime.java │ │ │ │ │ ├── CrimeModel.java │ │ │ │ │ ├── CrimePresenter.java │ │ │ │ │ ├── CrimeView.java │ │ │ │ │ └── StandardCrimeModel.java │ │ │ │ └── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ └── DataEventListener.java │ │ │ │ └── platform │ │ │ │ ├── CrimeActivity.java │ │ │ │ ├── CrimeFragment.java │ │ │ │ └── FragmentCrimeView.java │ │ └── res │ │ │ ├── layout │ │ │ ├── activity_crime.xml │ │ │ └── fragment_crime.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── criminalintent │ │ └── domain │ │ └── crime │ │ ├── CrimePresenterTest.java │ │ └── StandardCrimeModelTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter8-criminalintent-challenges ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── criminalintent │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── criminalintent │ │ │ │ ├── domain │ │ │ │ ├── crime │ │ │ │ │ ├── Crime.java │ │ │ │ │ ├── CrimeModel.java │ │ │ │ │ ├── CrimePresenter.java │ │ │ │ │ ├── CrimeView.java │ │ │ │ │ └── StandardCrimeModel.java │ │ │ │ └── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ └── DataEventListener.java │ │ │ │ └── platform │ │ │ │ ├── CrimeActivity.java │ │ │ │ ├── CrimeFragment.java │ │ │ │ └── FragmentCrimeView.java │ │ └── res │ │ │ ├── layout-land │ │ │ └── fragment_crime.xml │ │ │ ├── layout │ │ │ ├── activity_crime.xml │ │ │ └── fragment_crime.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── criminalintent │ │ └── domain │ │ └── crime │ │ ├── CrimePresenterTest.java │ │ └── StandardCrimeModelTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle ├── chapter8-criminalintent ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── criminalintent │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── olerass │ │ │ │ └── pfexample │ │ │ │ └── android │ │ │ │ └── criminalintent │ │ │ │ ├── domain │ │ │ │ ├── crime │ │ │ │ │ ├── Crime.java │ │ │ │ │ ├── CrimeModel.java │ │ │ │ │ ├── CrimePresenter.java │ │ │ │ │ ├── CrimeView.java │ │ │ │ │ └── StandardCrimeModel.java │ │ │ │ └── event │ │ │ │ │ ├── DataEvent.java │ │ │ │ │ └── DataEventListener.java │ │ │ │ └── platform │ │ │ │ ├── CrimeActivity.java │ │ │ │ ├── CrimeFragment.java │ │ │ │ └── FragmentCrimeView.java │ │ └── res │ │ │ ├── layout-land │ │ │ └── fragment_crime.xml │ │ │ ├── layout │ │ │ ├── activity_crime.xml │ │ │ └── fragment_crime.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── criminalintent │ │ └── domain │ │ └── crime │ │ ├── CrimePresenterTest.java │ │ └── StandardCrimeModelTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle └── chapter9-criminalintent ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── olerass │ │ └── pfexample │ │ └── android │ │ └── criminalintent │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── olerass │ │ │ └── pfexample │ │ │ └── android │ │ │ └── criminalintent │ │ │ ├── domain │ │ │ ├── crime │ │ │ │ ├── Crime.java │ │ │ │ ├── CrimeModel.java │ │ │ │ ├── CrimePresenter.java │ │ │ │ ├── CrimeView.java │ │ │ │ └── StandardCrimeModel.java │ │ │ ├── crimes │ │ │ │ ├── CrimeLab.java │ │ │ │ ├── CrimeListModel.java │ │ │ │ ├── CrimeListPresenter.java │ │ │ │ ├── CrimeListView.java │ │ │ │ └── StandardCrimeListModel.java │ │ │ └── event │ │ │ │ ├── DataEvent.java │ │ │ │ └── DataEventListener.java │ │ │ └── platform │ │ │ ├── SingleFragmentActivity.java │ │ │ ├── crime │ │ │ ├── CrimeActivity.java │ │ │ ├── CrimeFragment.java │ │ │ └── FragmentCrimeView.java │ │ │ └── crimes │ │ │ ├── CrimeListActivity.java │ │ │ ├── CrimeListFragment.java │ │ │ └── FragmentCrimeListView.java │ └── res │ │ ├── layout-land │ │ └── fragment_crime.xml │ │ ├── layout │ │ ├── activity_fragment.xml │ │ ├── fragment_crime.xml │ │ ├── fragment_crime_list.xml │ │ └── list_item_crime.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── olerass │ └── pfexample │ └── android │ └── criminalintent │ └── domain │ ├── crime │ ├── CrimeLabTest.java │ ├── CrimePresenterTest.java │ └── StandardCrimeModelTest.java │ └── crimes │ ├── CrimeListPresenterTest.java │ └── StandardCrimeListModelTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots.png └── settings.gradle /chapter1-geoquiz/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /chapter1-geoquiz/README.md: -------------------------------------------------------------------------------- 1 | # Presenter First Android - GeoQuiz Chapter 1 2 | 3 | Single-activity app that displays a question. The user may answer true or false and will be notified whether the answer was correct or not. 4 | 5 | ![Screenshots](screenshots.png?raw=true) -------------------------------------------------------------------------------- /chapter1-geoquiz/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'me.tatarka.retrolambda' 3 | 4 | android { 5 | compileSdkVersion 22 6 | buildToolsVersion "23.0.2" 7 | 8 | defaultConfig { 9 | applicationId "com.olerass.pfexample.android.geoquiz" 10 | minSdkVersion 16 11 | targetSdkVersion 22 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_8 23 | targetCompatibility JavaVersion.VERSION_1_8 24 | } 25 | } 26 | 27 | dependencies { 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | compile 'com.android.support:appcompat-v7:22.2.1' 30 | testCompile 'junit:junit:4.12' 31 | testCompile 'org.mockito:mockito-core:1.10.19' 32 | } 33 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\olerass\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/androidTest/java/com/olerass/pfexample/android/geoquiz/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEvent.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataEvent { 7 | private List> listeners = new ArrayList<>(); 8 | 9 | public void addListener(DataEventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch(T data) { 14 | for (DataEventListener listener : listeners) { 15 | listener.onDispatch(data); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface DataEventListener { 4 | void onDispatch(T data); 5 | } 6 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/Question.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class Question { 4 | private String text; 5 | private boolean correctAnswer; 6 | 7 | public Question(String text, boolean correctAnswer) { 8 | this.text = text; 9 | this.correctAnswer = correctAnswer; 10 | } 11 | 12 | public String getText() { 13 | return text; 14 | } 15 | 16 | public boolean getCorrectAnswer() { 17 | return correctAnswer; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public interface QuestionModel { 4 | String getQuestionText(); 5 | boolean isCorrectAnswer(boolean answer); 6 | } 7 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionPresenter.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class QuestionPresenter { 4 | private QuestionView view; 5 | private QuestionModel model; 6 | 7 | public QuestionPresenter(QuestionView view, QuestionModel model) { 8 | this.view = view; 9 | this.model = model; 10 | initialize(); 11 | } 12 | 13 | private void initialize() { 14 | view.setQuestionText(model.getQuestionText()); 15 | 16 | view.whenAnswerGiven(answer -> { 17 | if (model.isCorrectAnswer(answer)) { 18 | view.showCorrectAnswerMessage(); 19 | } else { 20 | view.showIncorrectAnswerMessage(); 21 | } 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.DataEventListener; 4 | 5 | public interface QuestionView { 6 | void setQuestionText(String question); 7 | void showCorrectAnswerMessage(); 8 | void showIncorrectAnswerMessage(); 9 | 10 | void whenAnswerGiven(DataEventListener listener); 11 | } 12 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/StandardQuestionModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class StandardQuestionModel implements QuestionModel { 4 | private Question question; 5 | 6 | public StandardQuestionModel(Question question) { 7 | this.question = question; 8 | } 9 | 10 | @Override 11 | public String getQuestionText() { 12 | return question.getText(); 13 | } 14 | 15 | @Override 16 | public boolean isCorrectAnswer(boolean answer) { 17 | return answer == question.getCorrectAnswer(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter1-geoquiz/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter1-geoquiz/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter1-geoquiz/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter1-geoquiz/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter1-geoquiz/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PFGeoQuiz 3 | Constantinople is the largest city in Turkey 4 | True 5 | False 6 | Correct! 7 | Incorrect! 8 | 9 | -------------------------------------------------------------------------------- /chapter1-geoquiz/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter1-geoquiz/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chapter1-geoquiz/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /chapter1-geoquiz/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter1-geoquiz/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chapter1-geoquiz/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /chapter1-geoquiz/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter1-geoquiz/screenshots.png -------------------------------------------------------------------------------- /chapter1-geoquiz/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/README.md: -------------------------------------------------------------------------------- 1 | # Presenter First Android - GeoQuiz Chapter 2 (Challenges) 2 | 3 | Chapter 2 app with added functionality for cycling both back and forth between the questions. Furthermore, the navigation buttons now use images and touching the textview advances the question. 4 | 5 | ![Screenshots](screenshots.png?raw=true) -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'me.tatarka.retrolambda' 3 | 4 | android { 5 | compileSdkVersion 22 6 | buildToolsVersion "23.0.2" 7 | 8 | defaultConfig { 9 | applicationId "com.olerass.pfexample.android.geoquiz" 10 | minSdkVersion 16 11 | targetSdkVersion 22 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_8 23 | targetCompatibility JavaVersion.VERSION_1_8 24 | } 25 | } 26 | 27 | dependencies { 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | compile 'com.android.support:appcompat-v7:22.2.1' 30 | testCompile 'junit:junit:4.12' 31 | testCompile 'org.mockito:mockito-core:1.10.19' 32 | } 33 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\olerass\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/androidTest/java/com/olerass/pfexample/android/geoquiz/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEvent.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataEvent { 7 | private List> listeners = new ArrayList<>(); 8 | 9 | public void addListener(DataEventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch(T data) { 14 | for (DataEventListener listener : listeners) { 15 | listener.onDispatch(data); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface DataEventListener { 4 | void onDispatch(T data); 5 | } 6 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/Event.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Event { 7 | private List listeners = new ArrayList<>(); 8 | 9 | public void addListener(EventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch() { 14 | for (EventListener listener : listeners) { 15 | listener.onDispatch(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/EventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface EventListener { 4 | void onDispatch(); 5 | } 6 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/Question.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class Question { 4 | private String text; 5 | private boolean correctAnswer; 6 | 7 | public Question(String text, boolean correctAnswer) { 8 | this.text = text; 9 | this.correctAnswer = correctAnswer; 10 | } 11 | 12 | public String getText() { 13 | return text; 14 | } 15 | 16 | public boolean getCorrectAnswer() { 17 | return correctAnswer; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 4 | 5 | public interface QuestionModel { 6 | String getQuestionText(); 7 | boolean isCorrectAnswer(boolean answer); 8 | void gotoNextQuestion(); 9 | void gotoPreviousQuestion(); 10 | 11 | void whenQuestionTextChanged(EventListener listener); 12 | } 13 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.DataEventListener; 4 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 5 | 6 | public interface QuestionView { 7 | void setQuestionText(String question); 8 | void showCorrectAnswerMessage(); 9 | void showIncorrectAnswerMessage(); 10 | 11 | void whenAnswerGiven(DataEventListener listener); 12 | void whenNextQuestionRequested(EventListener listener); 13 | void whenPreviousQuestionRequested(EventListener listener); 14 | } -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/drawable-hdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/drawable-hdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/drawable-hdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/drawable-hdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/drawable-mdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/drawable-mdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/drawable-mdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/drawable-mdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/drawable-xhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/drawable-xhdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/drawable-xhdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/drawable-xhdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/drawable-xxhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/drawable-xxhdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/drawable-xxhdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/drawable-xxhdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz-challenges/screenshots.png -------------------------------------------------------------------------------- /chapter2-geoquiz-challenges/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /chapter2-geoquiz/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /chapter2-geoquiz/README.md: -------------------------------------------------------------------------------- 1 | # Presenter First Android - GeoQuiz Chapter 2 2 | 3 | Chapter 1 app expanded with functionality for showing 5 different questions and forwards-cycling through them using a next button. 4 | 5 | ![Screenshots](screenshots.png?raw=true) -------------------------------------------------------------------------------- /chapter2-geoquiz/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'me.tatarka.retrolambda' 3 | 4 | android { 5 | compileSdkVersion 22 6 | buildToolsVersion "23.0.2" 7 | 8 | defaultConfig { 9 | applicationId "com.olerass.pfexample.android.geoquiz" 10 | minSdkVersion 16 11 | targetSdkVersion 22 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_8 23 | targetCompatibility JavaVersion.VERSION_1_8 24 | } 25 | } 26 | 27 | dependencies { 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | compile 'com.android.support:appcompat-v7:22.2.1' 30 | testCompile 'junit:junit:4.12' 31 | testCompile 'org.mockito:mockito-core:1.10.19' 32 | } 33 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\olerass\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/androidTest/java/com/olerass/pfexample/android/geoquiz/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEvent.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataEvent { 7 | private List> listeners = new ArrayList<>(); 8 | 9 | public void addListener(DataEventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch(T data) { 14 | for (DataEventListener listener : listeners) { 15 | listener.onDispatch(data); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface DataEventListener { 4 | void onDispatch(T data); 5 | } 6 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/Event.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Event { 7 | private List listeners = new ArrayList<>(); 8 | 9 | public void addListener(EventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch() { 14 | for (EventListener listener : listeners) { 15 | listener.onDispatch(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/EventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface EventListener { 4 | void onDispatch(); 5 | } 6 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/Question.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class Question { 4 | private String text; 5 | private boolean correctAnswer; 6 | 7 | public Question(String text, boolean correctAnswer) { 8 | this.text = text; 9 | this.correctAnswer = correctAnswer; 10 | } 11 | 12 | public String getText() { 13 | return text; 14 | } 15 | 16 | public boolean getCorrectAnswer() { 17 | return correctAnswer; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 4 | 5 | public interface QuestionModel { 6 | String getQuestionText(); 7 | boolean isCorrectAnswer(boolean answer); 8 | void gotoNextQuestion(); 9 | 10 | void whenQuestionTextChanged(EventListener listener); 11 | } 12 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionPresenter.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class QuestionPresenter { 4 | private QuestionView view; 5 | private QuestionModel model; 6 | 7 | public QuestionPresenter(QuestionView view, QuestionModel model) { 8 | this.view = view; 9 | this.model = model; 10 | initialize(); 11 | } 12 | 13 | private void initialize() { 14 | syncViewToModel(); 15 | 16 | view.whenAnswerGiven(answer -> { 17 | if (model.isCorrectAnswer(answer)) { 18 | view.showCorrectAnswerMessage(); 19 | } else { 20 | view.showIncorrectAnswerMessage(); 21 | } 22 | }); 23 | 24 | view.whenNextQuestionRequested(model::gotoNextQuestion); 25 | model.whenQuestionTextChanged(this::syncViewToModel); 26 | } 27 | 28 | private void syncViewToModel() { 29 | view.setQuestionText(model.getQuestionText()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.DataEventListener; 4 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 5 | 6 | public interface QuestionView { 7 | void setQuestionText(String question); 8 | void showCorrectAnswerMessage(); 9 | void showIncorrectAnswerMessage(); 10 | 11 | void whenAnswerGiven(DataEventListener listener); 12 | void whenNextQuestionRequested(EventListener listener); 13 | } 14 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/drawable-hdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/drawable-hdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/drawable-hdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/drawable-hdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/drawable-mdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/drawable-mdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/drawable-mdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/drawable-mdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/drawable-xhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/drawable-xhdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/drawable-xhdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/drawable-xhdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/drawable-xxhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/drawable-xxhdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/drawable-xxhdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/drawable-xxhdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PFGeoQuiz 3 | True 4 | False 5 | Correct! 6 | Incorrect! 7 | Next 8 | The Pacific ocean is larger than the Atlantic Ocean. 9 | The Suez Canal connects the Red Sea and the Indian Ocean. 10 | The Amazon source of the Nile River is in Egypt. 11 | The Amazon River is the longest river in the Americas. 12 | Lake Baikal is the world\'s oldest and deepest freshwater lake. 13 | 14 | -------------------------------------------------------------------------------- /chapter2-geoquiz/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter2-geoquiz/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chapter2-geoquiz/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /chapter2-geoquiz/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chapter2-geoquiz/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /chapter2-geoquiz/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter2-geoquiz/screenshots.png -------------------------------------------------------------------------------- /chapter2-geoquiz/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /chapter3-geoquiz/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /chapter3-geoquiz/README.md: -------------------------------------------------------------------------------- 1 | # Presenter First Android - GeoQuiz Chapter 3 2 | 3 | Chapter 2 app expanded with functionality for saving/restoring the active question across rotations by overriding `onSaveInstanceState`. 4 | 5 | ![Screenshots](screenshots.png?raw=true) 6 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'me.tatarka.retrolambda' 3 | 4 | android { 5 | compileSdkVersion 22 6 | buildToolsVersion "23.0.2" 7 | 8 | defaultConfig { 9 | applicationId "com.olerass.pfexample.android.geoquiz" 10 | minSdkVersion 16 11 | targetSdkVersion 22 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_8 23 | targetCompatibility JavaVersion.VERSION_1_8 24 | } 25 | } 26 | 27 | dependencies { 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | compile 'com.android.support:appcompat-v7:22.2.1' 30 | testCompile 'junit:junit:4.12' 31 | testCompile 'org.mockito:mockito-core:1.10.19' 32 | } 33 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\olerass\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/androidTest/java/com/olerass/pfexample/android/geoquiz/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEvent.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataEvent { 7 | private List> listeners = new ArrayList<>(); 8 | 9 | public void addListener(DataEventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch(T data) { 14 | for (DataEventListener listener : listeners) { 15 | listener.onDispatch(data); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface DataEventListener { 4 | void onDispatch(T data); 5 | } 6 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/Event.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Event { 7 | private List listeners = new ArrayList<>(); 8 | 9 | public void addListener(EventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch() { 14 | for (EventListener listener : listeners) { 15 | listener.onDispatch(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/EventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface EventListener { 4 | void onDispatch(); 5 | } 6 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/Question.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class Question { 4 | private String text; 5 | private boolean correctAnswer; 6 | 7 | public Question(String text, boolean correctAnswer) { 8 | this.text = text; 9 | this.correctAnswer = correctAnswer; 10 | } 11 | 12 | public String getText() { 13 | return text; 14 | } 15 | 16 | public boolean getCorrectAnswer() { 17 | return correctAnswer; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 4 | 5 | public interface QuestionModel { 6 | String getQuestionText(); 7 | boolean isCorrectAnswer(boolean answer); 8 | void gotoNextQuestion(); 9 | 10 | void whenQuestionTextChanged(EventListener listener); 11 | } 12 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionPresenter.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class QuestionPresenter { 4 | private QuestionView view; 5 | private QuestionModel model; 6 | 7 | public QuestionPresenter(QuestionView view, QuestionModel model) { 8 | this.view = view; 9 | this.model = model; 10 | initialize(); 11 | } 12 | 13 | private void initialize() { 14 | syncViewToModel(); 15 | 16 | view.whenAnswerGiven(answer -> { 17 | if (model.isCorrectAnswer(answer)) { 18 | view.showCorrectAnswerMessage(); 19 | } else { 20 | view.showIncorrectAnswerMessage(); 21 | } 22 | }); 23 | 24 | view.whenNextQuestionRequested(model::gotoNextQuestion); 25 | model.whenQuestionTextChanged(this::syncViewToModel); 26 | } 27 | 28 | private void syncViewToModel() { 29 | view.setQuestionText(model.getQuestionText()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.DataEventListener; 4 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 5 | 6 | public interface QuestionView { 7 | void setQuestionText(String question); 8 | void showCorrectAnswerMessage(); 9 | void showIncorrectAnswerMessage(); 10 | 11 | void whenAnswerGiven(DataEventListener listener); 12 | void whenNextQuestionRequested(EventListener listener); 13 | } 14 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/state/AndroidStateManager.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.state; 2 | 3 | import android.os.Bundle; 4 | 5 | public class AndroidStateManager implements StateSaver, StateLoader { 6 | private Bundle bundle; 7 | 8 | public AndroidStateManager(Bundle bundle) { 9 | this.bundle = bundle; 10 | } 11 | 12 | @Override 13 | public void saveInt(String key, int value) { 14 | bundle.putInt(key, value); 15 | } 16 | 17 | @Override 18 | public int loadInt(String key, int defaultIfNotFound) { 19 | if (bundle == null) { 20 | return defaultIfNotFound; 21 | } 22 | return bundle.getInt(key, defaultIfNotFound); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/state/StateLoader.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.state; 2 | 3 | public interface StateLoader { 4 | int loadInt(String key, int defaultIfNotFound); 5 | } -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/state/StateSaver.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.state; 2 | 3 | public interface StateSaver { 4 | void saveInt(String key, int value); 5 | } -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/drawable-hdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/drawable-hdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/drawable-hdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/drawable-hdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/drawable-mdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/drawable-mdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/drawable-mdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/drawable-mdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/drawable-xhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/drawable-xhdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/drawable-xhdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/drawable-xhdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/drawable-xxhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/drawable-xxhdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/drawable-xxhdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/drawable-xxhdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PFGeoQuiz 3 | True 4 | False 5 | Correct! 6 | Incorrect! 7 | Next 8 | The Pacific ocean is larger than the Atlantic Ocean. 9 | The Suez Canal connects the Red Sea and the Indian Ocean. 10 | The Amazon source of the Nile River is in Egypt. 11 | The Amazon River is the longest river in the Americas. 12 | Lake Baikal is the world\'s oldest and deepest freshwater lake. 13 | 14 | -------------------------------------------------------------------------------- /chapter3-geoquiz/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter3-geoquiz/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chapter3-geoquiz/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /chapter3-geoquiz/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chapter3-geoquiz/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /chapter3-geoquiz/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter3-geoquiz/screenshots.png -------------------------------------------------------------------------------- /chapter3-geoquiz/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/README.md: -------------------------------------------------------------------------------- 1 | # Presenter First Android - GeoQuiz Chapter 5 2 | 3 | Chapter 5 app with added functionality that prevents users from cheating when cheating (!). This version ensures that the cheating status are saved across rotations. Furthermore it's saved for each question so that it's not possible to cycle through the questions to reset the status. 4 | 5 | ![Screenshots](screenshots.png?raw=true) 6 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'me.tatarka.retrolambda' 3 | 4 | android { 5 | compileSdkVersion 22 6 | buildToolsVersion "23.0.2" 7 | 8 | defaultConfig { 9 | applicationId "com.olerass.pfexample.android.geoquiz" 10 | minSdkVersion 16 11 | targetSdkVersion 22 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_8 23 | targetCompatibility JavaVersion.VERSION_1_8 24 | } 25 | } 26 | 27 | dependencies { 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | compile 'com.android.support:appcompat-v7:22.2.1' 30 | testCompile 'junit:junit:4.12' 31 | testCompile 'org.mockito:mockito-core:1.10.19' 32 | } 33 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\olerass\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/androidTest/java/com/olerass/pfexample/android/geoquiz/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/cheat/CheatModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.cheat; 2 | 3 | public interface CheatModel { 4 | String getCorrectAnswer(); 5 | void setAnswerShown(boolean answerShown); 6 | } 7 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/cheat/CheatPresenter.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.cheat; 2 | 3 | public class CheatPresenter { 4 | private CheatView view; 5 | private CheatModel model; 6 | 7 | public CheatPresenter(CheatView view, CheatModel model) { 8 | this.view = view; 9 | this.model = model; 10 | initialize(); 11 | } 12 | 13 | private void initialize() { 14 | view.whenShowAnswerRequested(() -> { 15 | view.setAnswer(model.getCorrectAnswer()); 16 | model.setAnswerShown(true); 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/cheat/CheatView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.cheat; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 4 | 5 | public interface CheatView { 6 | void setAnswer(String answer); 7 | 8 | void whenShowAnswerRequested(EventListener listener); 9 | } -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEvent.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataEvent { 7 | private List> listeners = new ArrayList<>(); 8 | 9 | public void addListener(DataEventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch(T data) { 14 | for (DataEventListener listener : listeners) { 15 | listener.onDispatch(data); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/DataEventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface DataEventListener { 4 | void onDispatch(T data); 5 | } 6 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/Event.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Event { 7 | private List listeners = new ArrayList<>(); 8 | 9 | public void addListener(EventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch() { 14 | for (EventListener listener : listeners) { 15 | listener.onDispatch(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/event/EventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.event; 2 | 3 | public interface EventListener { 4 | void onDispatch(); 5 | } 6 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/Question.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | public class Question { 4 | private String text; 5 | private boolean correctAnswer; 6 | 7 | public Question(String text, boolean correctAnswer) { 8 | this.text = text; 9 | this.correctAnswer = correctAnswer; 10 | } 11 | 12 | public String getText() { 13 | return text; 14 | } 15 | 16 | public boolean getCorrectAnswer() { 17 | return correctAnswer; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 4 | 5 | public interface QuestionModel { 6 | String getQuestionText(); 7 | boolean hasCheatedOnCurrentQuestion(); 8 | boolean isCorrectAnswer(boolean answer); 9 | void gotoNextQuestion(); 10 | 11 | void cheatRequested(); 12 | void whenQuestionTextChanged(EventListener listener); 13 | } 14 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/question/QuestionView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.question; 2 | 3 | import com.olerass.pfexample.android.geoquiz.domain.event.DataEventListener; 4 | import com.olerass.pfexample.android.geoquiz.domain.event.EventListener; 5 | 6 | public interface QuestionView { 7 | void setQuestionText(String question); 8 | void showCorrectAnswerMessage(); 9 | void showIncorrectAnswerMessage(); 10 | void showCheaterMessage(); 11 | 12 | void whenAnswerGiven(DataEventListener listener); 13 | void whenNextQuestionRequested(EventListener listener); 14 | void whenCheatRequested(EventListener listener); 15 | } 16 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/state/StateLoader.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.state; 2 | 3 | public interface StateLoader { 4 | int loadInt(String key, int defaultIfNotFound); 5 | boolean loadBool(String key, boolean defaultIfNotFound); 6 | } -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/java/com/olerass/pfexample/android/geoquiz/domain/state/StateSaver.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.geoquiz.domain.state; 2 | 3 | public interface StateSaver { 4 | void saveInt(String key, int value); 5 | void saveBool(String key, boolean value); 6 | } -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/drawable-hdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/drawable-hdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/drawable-hdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/drawable-hdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/drawable-mdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/drawable-mdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/drawable-mdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/drawable-mdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/drawable-xhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/drawable-xhdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/drawable-xhdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/drawable-xhdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/drawable-xxhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/drawable-xxhdpi/arrow_left.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/drawable-xxhdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/drawable-xxhdpi/arrow_right.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter5-geoquiz-challenges/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | > 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /chapter5-geoquiz-challenges/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 | 9 | 10 | -------------------------------------------------------------------------------- /chapter5-geoquiz/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter5-geoquiz/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter5-geoquiz/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /chapter5-geoquiz/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 | 9 | 10 | -------------------------------------------------------------------------------- /chapter6-geoquiz-challenges/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter6-geoquiz-challenges/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter6-geoquiz-challenges/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /chapter6-geoquiz-challenges/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter7-criminalintent/app/src/test/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimePresenterTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import com.olerass.pfexample.android.criminalintent.domain.event.DataEventListener; 4 | 5 | import org.junit.Test; 6 | import org.mockito.ArgumentCaptor; 7 | 8 | import static org.mockito.Mockito.mock; 9 | import static org.mockito.Mockito.verify; 10 | 11 | public class CrimePresenterTest { 12 | @Test 13 | public void updatesModelWithTitleFromView_whenItChanges() { 14 | CrimeView view = mock(CrimeView.class); 15 | CrimeModel model = mock(CrimeModel.class); 16 | new CrimePresenter(view, model); 17 | 18 | ArgumentCaptor> argument = ArgumentCaptor.forClass((Class)DataEventListener.class); 19 | verify(view).whenTitleChanged(argument.capture()); 20 | argument.getValue().onDispatch("title"); 21 | 22 | verify(model).setTitle("title"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter7-criminalintent/app/src/test/java/com/olerass/pfexample/android/criminalintent/domain/crime/StandardCrimeModelTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.hamcrest.CoreMatchers.equalTo; 6 | import static org.hamcrest.CoreMatchers.is; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | 9 | public class StandardCrimeModelTest { 10 | @Test 11 | public void setTitle_setsTheTitleInBackingCrime_whenCalled() { 12 | Crime crime = new Crime(); 13 | StandardCrimeModel model = new StandardCrimeModel(crime); 14 | 15 | model.setTitle("title"); 16 | assertThat(crime.getTitle(), is(equalTo("title"))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter7-criminalintent/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chapter7-criminalintent/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /chapter7-criminalintent/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter7-criminalintent/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chapter7-criminalintent/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /chapter7-criminalintent/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter7-criminalintent/screenshots.png -------------------------------------------------------------------------------- /chapter7-criminalintent/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/README.md: -------------------------------------------------------------------------------- 1 | # Presenter First Android - CriminalIntent Chapter 8 (Challenges) 2 | 3 | Chapter 8 app with a custom crime date format using `DateFormat.format` 4 | 5 | ![Screenshots](screenshots.png?raw=true) 6 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\olerass\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/androidTest/java/com/olerass/pfexample/android/criminalintent/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/Crime.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | import java.util.UUID; 5 | 6 | public class Crime { 7 | private UUID id; 8 | private String title; 9 | private Date date; 10 | private boolean solved; 11 | 12 | public Crime() { 13 | id = UUID.randomUUID(); 14 | date = new Date(); 15 | } 16 | 17 | public UUID getId() { 18 | return id; 19 | } 20 | 21 | public String getTitle() { 22 | return title; 23 | } 24 | 25 | public void setTitle(String title) { 26 | this.title = title; 27 | } 28 | 29 | public Date getDate() { 30 | return date; 31 | } 32 | 33 | public void setDate(Date date) { 34 | this.date = date; 35 | } 36 | 37 | public boolean isSolved() { 38 | return solved; 39 | } 40 | 41 | public void setSolved(boolean solved) { 42 | this.solved = solved; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimeModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | 5 | public interface CrimeModel { 6 | Date getDate(); 7 | void setTitle(String title); 8 | void setSolved(boolean solved); 9 | } 10 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimePresenter.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | public class CrimePresenter { 4 | private CrimeView view; 5 | private CrimeModel model; 6 | 7 | public CrimePresenter(CrimeView view, CrimeModel model) { 8 | this.view = view; 9 | this.model = model; 10 | initialize(); 11 | } 12 | 13 | private void initialize() { 14 | view.setDate(model.getDate()); 15 | view.disableDateInteraction(); 16 | 17 | view.whenTitleChanged(model::setTitle); 18 | view.whenSolvedChanged(model::setSolved); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimeView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import com.olerass.pfexample.android.criminalintent.domain.event.DataEventListener; 4 | 5 | import java.util.Date; 6 | 7 | public interface CrimeView { 8 | void setDate(Date date); 9 | void disableDateInteraction(); 10 | 11 | void whenTitleChanged(DataEventListener listener); 12 | void whenSolvedChanged(DataEventListener listener); 13 | } 14 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/StandardCrimeModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | 5 | public class StandardCrimeModel implements CrimeModel { 6 | private Crime crime; 7 | 8 | public StandardCrimeModel(Crime crime) { 9 | this.crime = crime; 10 | } 11 | 12 | @Override 13 | public Date getDate() { 14 | return crime.getDate(); 15 | } 16 | 17 | @Override 18 | public void setTitle(String title) { 19 | crime.setTitle(title); 20 | } 21 | 22 | @Override 23 | public void setSolved(boolean solved) { 24 | crime.setSolved(solved); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/event/DataEvent.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataEvent { 7 | private List> listeners = new ArrayList<>(); 8 | 9 | public void addListener(DataEventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch(T data) { 14 | for (DataEventListener listener : listeners) { 15 | listener.onDispatch(data); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/event/DataEventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.event; 2 | 3 | public interface DataEventListener { 4 | void onDispatch(T data); 5 | } 6 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/java/com/olerass/pfexample/android/criminalintent/platform/CrimeActivity.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.platform; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | 8 | import com.olerass.pfexample.android.criminalintent.R; 9 | 10 | public class CrimeActivity extends AppCompatActivity { 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_crime); 15 | 16 | FragmentManager fm = getSupportFragmentManager(); 17 | Fragment fragment = fm.findFragmentById(R.id.fragment_container); 18 | if (fragment == null) { 19 | fragment = new CrimeFragment(); 20 | fm.beginTransaction().add(R.id.fragment_container, fragment).commit(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/layout/activity_crime.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent-challenges/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent-challenges/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent-challenges/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent-challenges/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent-challenges/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CriminalIntent 3 | Enter a title for the crime. 4 | Title 5 | Details 6 | Solved 7 | 8 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent-challenges/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent-challenges/screenshots.png -------------------------------------------------------------------------------- /chapter8-criminalintent-challenges/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /chapter8-criminalintent/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /chapter8-criminalintent/README.md: -------------------------------------------------------------------------------- 1 | # Presenter First Android - CriminalIntent Chapter 8 2 | 3 | Chapter 7 app expanded with more fields in the crime view including a date and solved status. 4 | 5 | ![Screenshots](screenshots.png?raw=true) 6 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\olerass\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/androidTest/java/com/olerass/pfexample/android/criminalintent/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/Crime.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | import java.util.UUID; 5 | 6 | public class Crime { 7 | private UUID id; 8 | private String title; 9 | private Date date; 10 | private boolean solved; 11 | 12 | public Crime() { 13 | id = UUID.randomUUID(); 14 | date = new Date(); 15 | } 16 | 17 | public UUID getId() { 18 | return id; 19 | } 20 | 21 | public String getTitle() { 22 | return title; 23 | } 24 | 25 | public void setTitle(String title) { 26 | this.title = title; 27 | } 28 | 29 | public Date getDate() { 30 | return date; 31 | } 32 | 33 | public void setDate(Date date) { 34 | this.date = date; 35 | } 36 | 37 | public boolean isSolved() { 38 | return solved; 39 | } 40 | 41 | public void setSolved(boolean solved) { 42 | this.solved = solved; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimeModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | 5 | public interface CrimeModel { 6 | Date getDate(); 7 | void setTitle(String title); 8 | void setSolved(boolean solved); 9 | } 10 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimePresenter.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | public class CrimePresenter { 4 | private CrimeView view; 5 | private CrimeModel model; 6 | 7 | public CrimePresenter(CrimeView view, CrimeModel model) { 8 | this.view = view; 9 | this.model = model; 10 | initialize(); 11 | } 12 | 13 | private void initialize() { 14 | view.setDate(model.getDate()); 15 | view.disableDateInteraction(); 16 | 17 | view.whenTitleChanged(model::setTitle); 18 | view.whenSolvedChanged(model::setSolved); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimeView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import com.olerass.pfexample.android.criminalintent.domain.event.DataEventListener; 4 | 5 | import java.util.Date; 6 | 7 | public interface CrimeView { 8 | void setDate(Date date); 9 | void disableDateInteraction(); 10 | 11 | void whenTitleChanged(DataEventListener listener); 12 | void whenSolvedChanged(DataEventListener listener); 13 | } 14 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/StandardCrimeModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | 5 | public class StandardCrimeModel implements CrimeModel { 6 | private Crime crime; 7 | 8 | public StandardCrimeModel(Crime crime) { 9 | this.crime = crime; 10 | } 11 | 12 | @Override 13 | public Date getDate() { 14 | return crime.getDate(); 15 | } 16 | 17 | @Override 18 | public void setTitle(String title) { 19 | crime.setTitle(title); 20 | } 21 | 22 | @Override 23 | public void setSolved(boolean solved) { 24 | crime.setSolved(solved); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/event/DataEvent.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataEvent { 7 | private List> listeners = new ArrayList<>(); 8 | 9 | public void addListener(DataEventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch(T data) { 14 | for (DataEventListener listener : listeners) { 15 | listener.onDispatch(data); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/event/DataEventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.event; 2 | 3 | public interface DataEventListener { 4 | void onDispatch(T data); 5 | } 6 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/platform/CrimeActivity.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.platform; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | 8 | import com.olerass.pfexample.android.criminalintent.R; 9 | 10 | public class CrimeActivity extends AppCompatActivity { 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_crime); 15 | 16 | FragmentManager fm = getSupportFragmentManager(); 17 | Fragment fragment = fm.findFragmentById(R.id.fragment_container); 18 | if (fragment == null) { 19 | fragment = new CrimeFragment(); 20 | fm.beginTransaction().add(R.id.fragment_container, fragment).commit(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/layout/activity_crime.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CriminalIntent 3 | Enter a title for the crime. 4 | Title 5 | Details 6 | Solved 7 | 8 | -------------------------------------------------------------------------------- /chapter8-criminalintent/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter8-criminalintent/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chapter8-criminalintent/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /chapter8-criminalintent/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chapter8-criminalintent/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /chapter8-criminalintent/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter8-criminalintent/screenshots.png -------------------------------------------------------------------------------- /chapter8-criminalintent/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /chapter9-criminalintent/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /chapter9-criminalintent/README.md: -------------------------------------------------------------------------------- 1 | # Presenter First Android - CriminalIntent Chapter 9 2 | 3 | Chapter 8 app expanded with a new activity for displaying a list of crimes using a `RecyclerView`. The crime view is not connected to the list view yet. 4 | 5 | ![Screenshots](screenshots.png?raw=true) 6 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\olerass\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/androidTest/java/com/olerass/pfexample/android/criminalintent/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/Crime.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | import java.util.UUID; 5 | 6 | public class Crime { 7 | private UUID id; 8 | private String title; 9 | private Date date; 10 | private boolean solved; 11 | 12 | public Crime() { 13 | id = UUID.randomUUID(); 14 | date = new Date(); 15 | } 16 | 17 | public UUID getId() { 18 | return id; 19 | } 20 | 21 | public String getTitle() { 22 | return title; 23 | } 24 | 25 | public void setTitle(String title) { 26 | this.title = title; 27 | } 28 | 29 | public Date getDate() { 30 | return date; 31 | } 32 | 33 | public void setDate(Date date) { 34 | this.date = date; 35 | } 36 | 37 | public boolean isSolved() { 38 | return solved; 39 | } 40 | 41 | public void setSolved(boolean solved) { 42 | this.solved = solved; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimeModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | 5 | public interface CrimeModel { 6 | Date getDate(); 7 | void setTitle(String title); 8 | void setSolved(boolean solved); 9 | } 10 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimePresenter.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | public class CrimePresenter { 4 | private CrimeView view; 5 | private CrimeModel model; 6 | 7 | public CrimePresenter(CrimeView view, CrimeModel model) { 8 | this.view = view; 9 | this.model = model; 10 | initialize(); 11 | } 12 | 13 | private void initialize() { 14 | view.setDate(model.getDate()); 15 | view.disableDateInteraction(); 16 | 17 | view.whenTitleChanged(model::setTitle); 18 | view.whenSolvedChanged(model::setSolved); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/CrimeView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import com.olerass.pfexample.android.criminalintent.domain.event.DataEventListener; 4 | 5 | import java.util.Date; 6 | 7 | public interface CrimeView { 8 | void setDate(Date date); 9 | void disableDateInteraction(); 10 | 11 | void whenTitleChanged(DataEventListener listener); 12 | void whenSolvedChanged(DataEventListener listener); 13 | } 14 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crime/StandardCrimeModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crime; 2 | 3 | import java.util.Date; 4 | 5 | public class StandardCrimeModel implements CrimeModel { 6 | private Crime crime; 7 | 8 | public StandardCrimeModel(Crime crime) { 9 | this.crime = crime; 10 | } 11 | 12 | @Override 13 | public Date getDate() { 14 | return crime.getDate(); 15 | } 16 | 17 | @Override 18 | public void setTitle(String title) { 19 | crime.setTitle(title); 20 | } 21 | 22 | @Override 23 | public void setSolved(boolean solved) { 24 | crime.setSolved(solved); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crimes/CrimeListModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crimes; 2 | 3 | import com.olerass.pfexample.android.criminalintent.domain.crime.Crime; 4 | 5 | import java.util.List; 6 | import java.util.UUID; 7 | 8 | public interface CrimeListModel { 9 | List getCrimes(); 10 | Crime getCrime(UUID uuid); 11 | } 12 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crimes/CrimeListPresenter.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crimes; 2 | 3 | import com.olerass.pfexample.android.criminalintent.domain.crime.Crime; 4 | 5 | public class CrimeListPresenter { 6 | private CrimeListView view; 7 | private CrimeListModel model; 8 | 9 | public CrimeListPresenter(CrimeListView view, CrimeListModel model) { 10 | this.view = view; 11 | this.model = model; 12 | initialize(); 13 | } 14 | 15 | private void initialize() { 16 | view.setCrimes(model.getCrimes()); 17 | view.whenCrimeSelected(uuid -> { 18 | Crime selected = model.getCrime(uuid); 19 | view.showCrimeMessage(selected.getTitle()); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crimes/CrimeListView.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crimes; 2 | 3 | import com.olerass.pfexample.android.criminalintent.domain.crime.Crime; 4 | import com.olerass.pfexample.android.criminalintent.domain.event.DataEventListener; 5 | 6 | import java.util.List; 7 | import java.util.UUID; 8 | 9 | public interface CrimeListView { 10 | void setCrimes(List crimes); 11 | void showCrimeMessage(String crimeTitle); 12 | 13 | void whenCrimeSelected(DataEventListener listener); 14 | } 15 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/crimes/StandardCrimeListModel.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.crimes; 2 | 3 | import com.olerass.pfexample.android.criminalintent.domain.crime.Crime; 4 | 5 | import java.util.List; 6 | import java.util.UUID; 7 | 8 | public class StandardCrimeListModel implements CrimeListModel { 9 | private CrimeLab lab; 10 | 11 | public StandardCrimeListModel(CrimeLab lab) { 12 | this.lab = lab; 13 | } 14 | 15 | @Override 16 | public List getCrimes() { 17 | return lab.getCrimes(); 18 | } 19 | 20 | @Override 21 | public Crime getCrime(UUID uuid) { 22 | return lab.getCrime(uuid); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/event/DataEvent.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.event; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataEvent { 7 | private List> listeners = new ArrayList<>(); 8 | 9 | public void addListener(DataEventListener listener) { 10 | listeners.add(listener); 11 | } 12 | 13 | public void dispatch(T data) { 14 | for (DataEventListener listener : listeners) { 15 | listener.onDispatch(data); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/domain/event/DataEventListener.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.domain.event; 2 | 3 | public interface DataEventListener { 4 | void onDispatch(T data); 5 | } 6 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/platform/crime/CrimeActivity.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.platform.crime; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | import com.olerass.pfexample.android.criminalintent.platform.SingleFragmentActivity; 6 | 7 | public class CrimeActivity extends SingleFragmentActivity { 8 | @Override 9 | protected Fragment createFragment() { 10 | return new CrimeFragment(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/java/com/olerass/pfexample/android/criminalintent/platform/crimes/CrimeListActivity.java: -------------------------------------------------------------------------------- 1 | package com.olerass.pfexample.android.criminalintent.platform.crimes; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | import com.olerass.pfexample.android.criminalintent.platform.SingleFragmentActivity; 6 | 7 | public class CrimeListActivity extends SingleFragmentActivity { 8 | @Override 9 | protected Fragment createFragment() { 10 | return new CrimeListFragment(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/layout/activity_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/layout/fragment_crime_list.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter9-criminalintent/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter9-criminalintent/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter9-criminalintent/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter9-criminalintent/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter9-criminalintent/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CriminalIntent 3 | Enter a title for the crime. 4 | Title 5 | Details 6 | Solved 7 | 8 | -------------------------------------------------------------------------------- /chapter9-criminalintent/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter9-criminalintent/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.5.0' 9 | classpath 'me.tatarka:gradle-retrolambda:3.2.4' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chapter9-criminalintent/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /chapter9-criminalintent/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter9-criminalintent/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chapter9-criminalintent/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /chapter9-criminalintent/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olerass/presenter-first-android/c29bd6c905989540e582b00f0f031cee9d02505c/chapter9-criminalintent/screenshots.png -------------------------------------------------------------------------------- /chapter9-criminalintent/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------