diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..eca48a8b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,47 @@ +before_install: cd source-code + +language: android +sudo: true +jdk: oraclejdk8 +env: + matrix: + - ADB_INSTALL_TIMEOUT=12 ANDROID_BUILD_TOOLS_VERSION=23.0.2 ANDROID_TARGET=android-23 ANDROID_ABI=armeabi-v7a + +android: + components: + - platform-tools + - tools + - build-tools-$ANDROID_BUILD_TOOLS_VERSION + - $ANDROID_TARGET + - android-23 + # Google Play Services + - extra-google-google_play_services + # Support library + - extra-android-support + # Latest artifacts in local repository + - extra-google-m2repository + - extra-android-m2repository + # Specify at least one system image, + - sys-img-armeabi-v7a-$ANDROID_TARGET + +before_script: + # Create and start emulator + - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI + - emulator -avd test -no-skin -no-audio -no-window & + - android-wait-for-emulator + - sleep 10 + - adb shell settings put global window_animation_scale 0 & + - adb shell settings put global transition_animation_scale 0 & + - adb shell settings put global animator_duration_scale 0 & + - adb shell input keyevent 82 & + +script: + - ./gradlew check connectedAndroidTest + +notifications: + email: + recipients: + - croozeus@gmail.com + - anupam.das.bwn@gmail.com + on_success: always + on_failure: always diff --git a/README.md b/README.md index 456341fb..c6ca44c1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,53 @@ +[![Build Status](https://travis-ci.org/BuildmLearn/BuildmLearn-Toolkit-Android.svg)](https://travis-ci.org/BuildmLearn/BuildmLearn-Toolkit-Android) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/05c83f4ecad84cc0a2e57d7ea39df41f)](https://www.codacy.com/app/anupam/BuildmLearn-Toolkit-Android?utm_source=github.com&utm_medium=referral&utm_content=BuildmLearn/BuildmLearn-Toolkit-Android&utm_campaign=Badge_Grade) + # BuildmLearn-Toolkit-Android -This repository contains the Android version of the BuildmLearn Toolkit. BuildmLearn Toolkit is an easy-to-use program that helps the users make mobile apps without any knowledge of application development. +This repository contains the Android version of the BuildmLearn Toolkit. BuildmLearn Toolkit app is an easy-to-use android app that helps the users make another mobile apps without any knowledge of android application development. The toolkit helps creating mobile application with various functionality and allows teachers to input their custom content. Targeted at teachers, this toolkit helps them make learning fun and engaging through mobile apps. + +# Development Setup +1. Go to the project repo and click the `Fork` button +2. Clone your forked repository : `git clone git@github.com:your_name/BuildmLearn-Toolkit-Android.git` +3. Move to android project folder `cd source-code` +4. Open the project with Android Studio + +Glosarry +====== +| Folders | Description | +| ------------- |:-------------| +| **source-code** | **Android Project Files** | +| **ui-design** | **Contains UI mockups and wireframes** | +| **[X]** | **source-code/app/src/main/java/org/buildmlearn/toolkit** | +| [X]/activity | Contains various activities | +| [X]/adapters | Contains various adapters | +| [X]/fragment | Contains various fragment | +| [X]/simulator | Contains simulator activity | +| [X]/templates | Contains various template activities | +| [X]/model | Contains KeyStoreDetails, SavedProject, TemplateInfos, Tutorial, etc | +| [X]/utilities | Contains various utilities including SignerThread | +| [X]/views | Contains text-view font support for old-backed SDKs | +| [X]/infotemplate | Contains simulator's code for Info Template | +| [X]/learnspelling | Contains simulator's code for learnspelling Template | +| [X]/flashcardtemplate | Contains simulator's code for FlashCard Template | +| [X]/quiztemplate | Contains simulator's code for Quiz Template | +| [X]/videocollectiontemplate | Contains simulator's code for FlashCard Template | +| [X]/comprehensiontemplate | Contains simulator's code for Comprehension Template | +| [X]/[?]/adapter | Contains simulator's adapter for [?] Template | +| [X]/[?]/data | Contains simulator's SQLiteDatabase code for [?] Template | +| [X]/[?]/fragment | Contains simulator's fragment for [?] Template | + +# How to build + +All dependencies are defined in ```source-code/app/build.gradle```. Import the project in Android Studio or use Gradle in command line: + +``` +./gradlew assembleRelease +``` + +The result apk file will be placed in ```source-code/app/build/outputs/apk/```. + +#Contribution policy + +All contributions should be done in **bug-fixes** branch. PRs must pass build check on Travis-CI. # License for use and distribution diff --git a/source-code/README.md b/source-code/README.md index cc6a79a2..3fd5d032 100644 --- a/source-code/README.md +++ b/source-code/README.md @@ -1,4 +1,29 @@ -## How to build +#This folder contains the project source-code + +Glosarry +====== +| Folders | Description | +| ------------- |:-------------| +| **[X]** | **app/src/main/java/org/buildmlearn/toolkit** | +| [X]/activity | Contains various activities | +| [X]/adapters | Contains various adapters | +| [X]/fragment | Contains various fragment | +| [X]/simulator | Contains simulator activity | +| [X]/templates | Contains various template activities | +| [X]/model | Contains KeyStoreDetails, SavedProject, TemplateInfos, Tutorial, etc | +| [X]/utilities | Contains various utilities including SignerThread | +| [X]/views | Contains text-view font support for old-backed SDKs | +| [X]/infotemplate | Contains simulator's code for Info Template | +| [X]/learnspelling | Contains simulator's code for learnspelling Template | +| [X]/flashcardtemplate | Contains simulator's code for FlashCard Template | +| [X]/quiztemplate | Contains simulator's code for Quiz Template | +| [X]/videocollectiontemplate | Contains simulator's code for FlashCard Template | +| [X]/comprehensiontemplate | Contains simulator's code for Comprehension Template | +| [X]/[?]/adapter | Contains simulator's adapter for [?] Template | +| [X]/[?]/data | Contains simulator's SQLiteDatabase code for [?] Template | +| [X]/[?]/fragment | Contains simulator's fragment for [?] Template | + +# How to build All dependencies are defined in ```app/build.gradle```. Import the project in Android Studio or use Gradle in command line: diff --git a/source-code/app/app.iml b/source-code/app/app.iml deleted file mode 100644 index 921e4f80..00000000 --- a/source-code/app/app.iml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source-code/app/build.gradle b/source-code/app/build.gradle index a6c6c8a9..40cc3c61 100644 --- a/source-code/app/build.gradle +++ b/source-code/app/build.gradle @@ -32,6 +32,8 @@ android { targetSdkVersion 23 versionCode 1 versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -42,21 +44,24 @@ android { signingConfig signingConfigs.config } } + lintOptions { + abortOnError false + } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:appcompat-v7:22.1.+' - compile 'com.android.support:cardview-v7:21.0.+' - compile 'com.android.support:recyclerview-v7:21.0.+' - compile 'com.android.support:design:22.2.1' + compile 'com.android.support:appcompat-v7:23.4.0' + compile 'com.android.support:cardview-v7:23.4.0' + compile 'com.android.support:recyclerview-v7:23.4.0' + compile 'com.android.support:design:23.4.0' compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') { transitive = true } compile('com.github.afollestad.material-dialogs:commons:0.8.5.3@aar') { transitive = true } - compile 'com.cocosw:bottomsheet:1.+@aar' + compile 'com.cocosw:bottomsheet:1.3.0@aar' compile('com.crashlytics.sdk.android:crashlytics:2.3.1@aar') { transitive = true; } @@ -69,8 +74,15 @@ dependencies { compile files('libs/kellinwood-logging-android-1.4.jar') compile files('libs/kellinwood-logging-lib-1.1.jar') compile files('libs/kellinwood-logging-log4j-1.0.jar') + compile files('libs/axml.jar') compile 'com.viewpagerindicator:library:2.4.1@aar' compile 'com.nineoldandroids:library:2.4.0' compile 'com.daimajia.easing:library:1.0.1@aar' compile 'com.daimajia.androidanimations:library:1.1.3@aar' -} + compile 'com.squareup.picasso:picasso:2.5.2' + compile 'org.jsoup:jsoup:1.9.1' + androidTestCompile 'com.android.support:support-annotations:23.4.0' + androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.0.0' +} \ No newline at end of file diff --git a/source-code/app/libs/axml.jar b/source-code/app/libs/axml.jar new file mode 100644 index 00000000..38f28feb Binary files /dev/null and b/source-code/app/libs/axml.jar differ diff --git a/source-code/app/src/androidTest/AndroidManifest.xml b/source-code/app/src/androidTest/AndroidManifest.xml new file mode 100644 index 00000000..16a0e04f --- /dev/null +++ b/source-code/app/src/androidTest/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/source-code/app/src/androidTest/java/org/buildmlearn/toolkit/espresso/ComprehensionTest.java b/source-code/app/src/androidTest/java/org/buildmlearn/toolkit/espresso/ComprehensionTest.java new file mode 100644 index 00000000..2c3a9b5e --- /dev/null +++ b/source-code/app/src/androidTest/java/org/buildmlearn/toolkit/espresso/ComprehensionTest.java @@ -0,0 +1,273 @@ +package org.buildmlearn.toolkit.espresso; + +import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.support.test.annotation.UiThreadTest; +import android.support.test.espresso.UiController; +import android.support.test.espresso.ViewAction; +import android.support.test.espresso.action.ViewActions; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiObjectNotFoundException; +import android.support.test.uiautomator.UiSelector; +import android.support.v7.widget.AppCompatTextView; +import android.test.suitebuilder.annotation.LargeTest; +import android.view.View; +import android.view.WindowManager; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.activity.TemplateEditor; +import org.buildmlearn.toolkit.constant.Constants; +import org.hamcrest.Matcher; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; + +import static android.support.test.InstrumentationRegistry.getInstrumentation; +import static android.support.test.espresso.Espresso.closeSoftKeyboard; +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.longClick; +import static android.support.test.espresso.action.ViewActions.replaceText; +import static android.support.test.espresso.action.ViewActions.scrollTo; +import static android.support.test.espresso.action.ViewActions.typeText; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withParent; +import static android.support.test.espresso.matcher.ViewMatchers.withResourceName; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.core.AllOf.allOf; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsAnything.anything; +import static org.hamcrest.core.IsInstanceOf.instanceOf; + +/** + * Created by anupam (opticod) on 7/6/16. + */ + +@Ignore +@RunWith(AndroidJUnit4.class) +@LargeTest +public class ComprehensionTest { + @Rule + public final ActivityTestRule mActivityRule = + new ActivityTestRule(TemplateEditor.class) { + @Override + protected Intent getActivityIntent() { + Context targetContext = getInstrumentation() + .getTargetContext(); + Intent result = new Intent(targetContext, TemplateEditor.class); + result.putExtra(Constants.TEMPLATE_ID, 5); + return result; + } + }; + + public static void sleep() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private static void allowPermissionsIfNeeded() { + if (Build.VERSION.SDK_INT >= 23) { + UiDevice device = UiDevice.getInstance(getInstrumentation()); + UiObject allowPermissions = device.findObject(new UiSelector().text("Allow")); + if (allowPermissions.exists()) { + try { + allowPermissions.click(); + } catch (UiObjectNotFoundException e) { + } + } + } + } + + @UiThreadTest + @Before + public void setUp() throws Throwable { + final Activity activity = mActivityRule.getActivity(); + mActivityRule.runOnUiThread(new Runnable() { + @Override + public void run() { + KeyguardManager mKG = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); + KeyguardManager.KeyguardLock mLock = mKG.newKeyguardLock(Context.KEYGUARD_SERVICE); + mLock.disableKeyguard(); + + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON); + } + }); + } + + public void toolbarTitle() { + String title = "Comprehension Template"; + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)))) + .check(matches(withText(title))); + } + + public void addMetaDetails() { + String passTitle = "PassageTitle"; + String passage = "Short Passage."; + String timer = "180"; + + onView(withId(R.id.button_add_item)).perform(click()); + closeSoftKeyboard(); + onView(withId(R.id.meta_title)).perform(typeText(passTitle)); + closeSoftKeyboard(); + onView(withId(R.id.meta_passage)).perform(typeText(passage), ViewActions.closeSoftKeyboard()); + sleep(); + onView(withId(R.id.meta_timer)).perform(scrollTo()); + sleep(); + onView(withId(R.id.meta_timer)).perform(click()).perform(typeText(timer), ViewActions.closeSoftKeyboard()); + sleep(); + onView(withResourceName("buttonDefaultPositive")).perform(click()); + + } + + public void editMetaDetails() { + String passTitle = "EditedPassageTitle"; + String passage = "EditedShort Passage."; + + onView(withId(R.id.template_meta_listview)).perform(longClick()); + onView(withId(R.id.action_edit)).perform(click()); + closeSoftKeyboard(); + onView(withId(R.id.meta_title)).perform(replaceText(passTitle)); + closeSoftKeyboard(); + onView(withId(R.id.meta_passage)).perform(replaceText(passage), ViewActions.closeSoftKeyboard()); + sleep(); + onView(withResourceName("buttonDefaultPositive")).perform(click()); + + } + + public void addQuestions() { + String question = "This is just a silly question whose answer is (b)."; + + onView(withId(R.id.button_add_item)).perform(click()); + onView(withId(R.id.quiz_question)).perform(typeText(question)); + closeSoftKeyboard(); + sleep(); + onView(withId(R.id.quiz_option_1)).perform(scrollTo()); + onView(withId(R.id.quiz_option_1)).perform(typeText("A")); + closeSoftKeyboard(); + sleep(); + onView(withId(R.id.quiz_option_2)).perform(scrollTo()); + onView(withId(R.id.quiz_option_2)).perform(typeText("B")); + closeSoftKeyboard(); + sleep(); + onView(withId(R.id.quiz_radio_2)).perform(scrollTo()).perform(click()); + closeSoftKeyboard(); + sleep(); + onView(withResourceName("buttonDefaultPositive")).perform(click()); + + } + + public void editQuestions() { + String question = "This is just a silly question whose answer changed to (a)."; + + onData(anything()).inAdapterView(withId(R.id.template_editor_listview)).atPosition(1).perform(longClick()); + onView(withId(R.id.action_edit)).perform(click()); + onView(withId(R.id.quiz_question)).perform(replaceText(question)); + closeSoftKeyboard(); + onView(withId(R.id.quiz_radio_1)).perform(scrollTo()).perform(click()); + closeSoftKeyboard(); + onView(withResourceName("buttonDefaultPositive")).perform(click()); + + } + + public void addTemplate() { + + onView(withId(R.id.author_name)).perform(replaceText("Anupam")); + onView(withId(R.id.template_title)).perform(replaceText("Testing template")); + } + + public void saveAPK() { + + onView(withId(R.id.action_save)).perform(click()); + onView(withText("Save APK")).perform(click()); + + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + String finalApk = getText(allOf(withResourceName("content"), is(instanceOf(AppCompatTextView.class)))); + finalApk = finalApk.substring(18, finalApk.length()); + File file = new File(finalApk); + intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); + mActivityRule.getActivity().startActivity(intent); + } + + private String getText(final Matcher matcher) { + final String[] stringHolder = {null}; + onView(matcher).perform(new ViewAction() { + @Override + public Matcher getConstraints() { + return isAssignableFrom(TextView.class); + } + + @Override + public String getDescription() { + return "getting text from a TextView"; + } + + @Override + public void perform(UiController uiController, View view) { + TextView tv = (TextView) view; + stringHolder[0] = tv.getText().toString(); + } + }); + return stringHolder[0]; + } + + public void checkSimulator() { + onView(withId(R.id.action_simulate)).perform(click()); + onView(withText("Testing template")).check(matches(isDisplayed())); + onView(withText("Anupam")).check(matches(isDisplayed())); + onView(withId(R.id.enter)).perform(click()); + String title = "EditedPassageTitle"; + String passage = "EditedShort Passage."; + onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.toolbar)), withText(title))) + .check(matches(isDisplayed())); + + onView(withId(R.id.passage)).check(matches(withText(passage))).check(matches(isDisplayed())); + + onView(withId(R.id.go_to_ques)).perform(scrollTo()).perform(click()); + + onView(withId(R.id.radioButton1)).perform(scrollTo()).perform(click()); + onView(withId(R.id.next)).perform(scrollTo()).perform(click()); + onView(withId(R.id.correct)).check(matches(withText("Total Correct : 1"))).check(matches(isDisplayed())); + onView(withId(R.id.wrong)).check(matches(withText("Total Wrong : 0"))).check(matches(isDisplayed())); + onView(withId(R.id.un_answered)).check(matches(withText("Total Unanswered : 0"))).check(matches(isDisplayed())); + + onView(withId(R.id.exit)).perform(click()); + + } + + @Test + public void testAllSerially() { + allowPermissionsIfNeeded(); + toolbarTitle(); + addTemplate(); + addMetaDetails(); + addQuestions(); + editMetaDetails(); + editQuestions(); + checkSimulator(); + saveAPK(); + } +} \ No newline at end of file diff --git a/source-code/app/src/debug/AndroidManifest.xml b/source-code/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..6de2f39a --- /dev/null +++ b/source-code/app/src/debug/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/source-code/app/src/main/AndroidManifest.xml b/source-code/app/src/main/AndroidManifest.xml index d23191da..43bd3cdd 100644 --- a/source-code/app/src/main/AndroidManifest.xml +++ b/source-code/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + + android:theme="@style/Buildmlearn.Simulator" /> diff --git a/source-code/app/src/main/assets/BasicmLearningApp.apk b/source-code/app/src/main/assets/BasicmLearningApp.apk old mode 100755 new mode 100644 index e517ea83..f9d10df4 Binary files a/source-code/app/src/main/assets/BasicmLearningApp.apk and b/source-code/app/src/main/assets/BasicmLearningApp.apk differ diff --git a/source-code/app/src/main/assets/ComprehensionApp.apk b/source-code/app/src/main/assets/ComprehensionApp.apk new file mode 100644 index 00000000..94c013ee Binary files /dev/null and b/source-code/app/src/main/assets/ComprehensionApp.apk differ diff --git a/source-code/app/src/main/assets/VideoCollectionApp.apk b/source-code/app/src/main/assets/VideoCollectionApp.apk new file mode 100644 index 00000000..9df21be9 Binary files /dev/null and b/source-code/app/src/main/assets/VideoCollectionApp.apk differ diff --git a/source-code/app/src/main/assets/template_assets/comprehension_content.xml b/source-code/app/src/main/assets/template_assets/comprehension_content.xml new file mode 100644 index 00000000..4282afcd --- /dev/null +++ b/source-code/app/src/main/assets/template_assets/comprehension_content.xml @@ -0,0 +1,31 @@ + + + + Anupam + + English Tutorial + + + Comprehension Practise + Dream of the Rarebit Fiend was a newspaper comic strip by American cartoonist Winsor McCay, begun September 10, 1904, that depicted fantastic bizarre dreams. It was McCay's second successful strip after Little Sammy Sneeze secured him a position on the cartoon staff of the New York Herald. Rarebit Fiend was printed in the Evening Telegram, a newspaper published by the Herald. The strip had no continuity or recurring characters. + + 180 + + + What was the position secured by the Little Sammy Sneeze? + + + + + 1 + + + What was the pen name of McCay? + + + + + 2 + + + diff --git a/source-code/app/src/main/assets/template_assets/video_content.xml b/source-code/app/src/main/assets/template_assets/video_content.xml new file mode 100644 index 00000000..061eb58c --- /dev/null +++ b/source-code/app/src/main/assets/template_assets/video_content.xml @@ -0,0 +1,36 @@ + + + + Anupam Das + + Popular Movies App Tutorial + + + Popular Movies Promo Video + This app help users to discover the most popular, the highest rated + and the highest-grossing movies. It reveals the power of adaptive UI both for phone + and tablet devices.It includes various new Lollipop+ features. + + https://www.youtube.com/watch?v=STsHnjp1jKk + https://i.ytimg.com/vi/STsHnjp1jKk/hqdefault.jpg + + + Udacity PopularMovies App Demo 1 + This app help users to discover the most popular, the highest rated + and the highest-grossing movies. It reveals the power of adaptive UI both for phone + and tablet devices.It includes various new Lollipop+ features. + + https://www.youtube.com/watch?v=YoyXolO2hhU + https://i.ytimg.com/vi/YoyXolO2hhU/hqdefault.jpg + + + Udacity PopularMovies App Demo 2 + This app help users to discover the most popular, the highest rated + and the highest-grossing movies. It reveals the power of adaptive UI both for phone + and tablet devices.It includes various new Lollipop+ features. + + https://www.youtube.com/watch?v=uHlaXrYLm6s + https://i.ytimg.com/vi/uHlaXrYLm6s/hqdefault.jpg + + + \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/ToolkitApplication.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/ToolkitApplication.java index 09c4052f..4cacac3d 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/ToolkitApplication.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/ToolkitApplication.java @@ -16,10 +16,6 @@ */ public class ToolkitApplication extends Application { - private String projectDir; - private String toolkitDir; - private String apkDir; - private String dir; private boolean isExternalStorageAvailable = false; @@ -50,6 +46,14 @@ public void onCreate() { } + /** + * @brief Returns external storage directory. + * @return folder file + */ + public File getDir() { + return Environment.getExternalStorageDirectory(); + } + /** * @brief Returns directory for BuildmLearn toolkit manually created files. * @return folder path @@ -87,7 +91,7 @@ public String getApkDir() { * @brief Checks if external storage is present for storing data * @return true if external storage is present, else false */ - private boolean checkExternalStorage() { + public boolean checkExternalStorage() { boolean result = false; File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/BuildmLearn123/"); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/AboutBuildmLearn.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/AboutBuildmLearn.java index 19de8da6..ef0d1170 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/AboutBuildmLearn.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/AboutBuildmLearn.java @@ -5,8 +5,6 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; import android.widget.TextView; import org.buildmlearn.toolkit.R; @@ -27,12 +25,14 @@ protected void onCreate(Bundle savedInstanceState) { setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); - PackageInfo pInfo = null; + PackageInfo pInfo; try { pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); String version = pInfo.versionName; + assert findViewById(R.id.app_version) != null; ((TextView)findViewById(R.id.app_version)).setText("Version: " + version); } catch (PackageManager.NameNotFoundException e) { + assert findViewById(R.id.app_version) != null; ((TextView)findViewById(R.id.app_version)).setText("Version: 1.0"); e.printStackTrace(); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/DeepLinkerActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/DeepLinkerActivity.java index bbe0128c..99e999fb 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/DeepLinkerActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/DeepLinkerActivity.java @@ -59,11 +59,7 @@ protected void onCreate(Bundle savedInstanceState) { } Toast.makeText(this, "Invalid project file", Toast.LENGTH_SHORT).show(); finish(); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { + } catch (ParserConfigurationException | IOException | SAXException e) { e.printStackTrace(); } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/FirstRunActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/FirstRunActivity.java index c0ef6b6a..859ba020 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/FirstRunActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/FirstRunActivity.java @@ -72,7 +72,7 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { editor.putString(getString(R.string.key_user_name), name.getText().toString()); editor.putBoolean(FIRST_RUN, true); - editor.commit(); + editor.apply(); Intent intent = new Intent(getApplicationContext(), TutorialActivity.class); intent.putExtra(Constants.START_ACTIVITY, true); startActivity(intent); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java index b24c8947..ccec49c1 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java @@ -6,34 +6,19 @@ import android.content.Intent; import android.os.Bundle; import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; -import android.widget.Toast; - -import com.crashlytics.android.Crashlytics; import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.fragment.NavigationDrawerFragment; import org.buildmlearn.toolkit.model.Section; -import io.fabric.sdk.android.Fabric; - /** * @brief Home screen of the application containg all the menus and settings. */ public class HomeActivity extends AppCompatActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks { - /** - * Fragment managing the behaviors, interactions and presentation of the navigation drawer. - */ - private NavigationDrawerFragment mNavigationDrawerFragment; - - /** - * Used to store the last screen title. For use in {@link #restoreActionBar()}. - */ - private CharSequence mTitle; private Section currentSection; /** @@ -48,9 +33,11 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_home); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); - mNavigationDrawerFragment = (NavigationDrawerFragment) + /* + Fragment managing the behaviors, interactions and presentation of the navigation drawer. + */ + NavigationDrawerFragment mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer); - mTitle = getTitle(); // Set up the drawer. mNavigationDrawerFragment.setUp( @@ -105,12 +92,4 @@ public void onNavigationDrawerItemSelected(int position) { } } - - public void restoreActionBar() { - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setTitle(mTitle); - } - - } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TemplateActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TemplateActivity.java index 744ec338..43088a46 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TemplateActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TemplateActivity.java @@ -5,8 +5,6 @@ import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; import android.widget.AbsListView; import android.widget.AdapterView; @@ -32,17 +30,16 @@ protected void onCreate(Bundle savedInstanceState) { ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeButtonEnabled(true); - ListAdapter mAdapter = new TemplateAdapter(this, 6); + ListAdapter mAdapter = new TemplateAdapter(this); AbsListView mListView = (AbsListView) findViewById(android.R.id.list); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - int templateId = position; Intent intent = new Intent(getApplicationContext(), TemplateEditor.class); - intent.putExtra(Constants.TEMPLATE_ID, templateId); + intent.putExtra(Constants.TEMPLATE_ID, position); startActivity(intent); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TemplateEditor.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TemplateEditor.java index dd7082e6..a70c610c 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TemplateEditor.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TemplateEditor.java @@ -1,17 +1,25 @@ package org.buildmlearn.toolkit.activity; +import android.Manifest; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.content.res.ColorStateList; +import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.preference.PreferenceManager; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.CardView; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.LayoutInflater; @@ -37,6 +45,7 @@ import org.buildmlearn.toolkit.model.TemplateInterface; import org.buildmlearn.toolkit.simulator.Simulator; import org.buildmlearn.toolkit.utilities.FileUtils; +import org.buildmlearn.toolkit.utilities.KeyboardHelper; import org.buildmlearn.toolkit.utilities.SignerThread; import org.w3c.dom.Attr; import org.w3c.dom.Document; @@ -62,20 +71,27 @@ public class TemplateEditor extends AppCompatActivity { - private final static String TAG = "TEMPLATE EDITOR"; - + private static final String TAG = "TEMPLATE EDITOR"; + private static final int PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE_RESULT = 100; + private final Handler handlerToast = new Handler() { + public void handleMessage(Message message) { + if (message.arg1 == -1) { + Toast.makeText(TemplateEditor.this, "Build unsuccessful", Toast.LENGTH_SHORT).show(); + } + } + }; private ListView templateEdtiorList; + private ListView templateMetaList; private int templateId; private Template template; private TemplateInterface selectedTemplate; private int selectedPosition = -1; private boolean showTemplateSelectedMenu; - private View selectedView = null; + private View selectedView; private ToolkitApplication toolkit; private String oldFileName; private MaterialDialog mApkGenerationDialog; - /** * {@inheritDoc} */ @@ -84,6 +100,9 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); oldFileName = null; setContentView(R.layout.activity_template_editor); + KeyboardHelper.hideKeyboard(this, findViewById(R.id.toolbar)); + KeyboardHelper.hideKeyboard(this,findViewById(R.id.template_editor_listview)); + KeyboardHelper.hideKeyboard(this,findViewById(R.id.empty)); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); toolkit = (ToolkitApplication) getApplicationContext(); templateId = getIntent().getIntExtra(Constants.TEMPLATE_ID, -1); @@ -108,11 +127,20 @@ protected void onCreate(Bundle savedInstanceState) { findViewById(R.id.button_add_item).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - selectedTemplate.addItem(TemplateEditor.this); - hideEmptyView(); + if (templateId == 5 && selectedTemplate.currentMetaEditorAdapter().isEmpty()) { + selectedTemplate.addMetaData(TemplateEditor.this); + } else { + selectedTemplate.addItem(TemplateEditor.this); + } } }); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE_RESULT); + } } /** @@ -136,6 +164,54 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); } + /** + * @param adapter Adapter containing template meta data + * @brief Populates meta ListView item by setting adapter to ListView. + */ + private void populateMetaView(final BaseAdapter adapter) { + if (templateMetaList == null) { + templateMetaList = (ListView) findViewById(R.id.template_meta_listview); + } + + setAdapterMeta(adapter); + + templateMetaList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + + Log.e(getClass().getName(), " " + position); + + if (selectedPosition == -2) { + selectedPosition = -1; + if (view instanceof CardView) { + ((CardView) view).setCardBackgroundColor(Color.WHITE); + } else { + view.setBackgroundResource(0); + } + restoreColorScheme(); + } else { + if (selectedView != null) { + if (selectedView instanceof CardView) { + ((CardView) selectedView).setCardBackgroundColor(Color.WHITE); + } else { + selectedView.setBackgroundResource(0); + } + } + selectedView = view; + selectedPosition = -2; + Log.d(TAG, "Position: " + selectedPosition); + + if (view instanceof CardView) { + ((CardView) view).setCardBackgroundColor(Color.LTGRAY); + } else { + view.setBackgroundColor(ContextCompat.getColor(toolkit, R.color.color_divider)); + } + changeColorScheme(); + } + return true; + } + }); + } /** * @param adapter Adapter containing template data @@ -143,39 +219,54 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) { *

* Header view contains the editable author name and template title fields. */ - protected void populateListView(final BaseAdapter adapter) { + private void populateListView(final BaseAdapter adapter) { if (templateEdtiorList == null) { templateEdtiorList = (ListView) findViewById(R.id.template_editor_listview); } - LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View templateHeader = inflater.inflate(R.layout.listview_header_template, templateEdtiorList, false); - templateEdtiorList.addHeaderView(templateHeader, null, false); + LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View templateHeader = inflater.inflate(R.layout.listview_header_template, templateEdtiorList, false); + templateEdtiorList.addHeaderView(templateHeader, null, false); + + EditText authorEditText = (EditText) findViewById(R.id.author_name); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + assert authorEditText != null; + authorEditText.setText(preferences.getString(getString(R.string.key_user_name), "")); - EditText authorEditText = (EditText) findViewById(R.id.author_name); - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - authorEditText.setText(preferences.getString(getString(R.string.key_user_name), "")); setAdapter(adapter); templateEdtiorList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + Log.e(getClass().getName(), " " + position); if (position == 0) { return false; } if (selectedPosition == position - 1) { selectedPosition = -1; - view.setBackgroundResource(0); + if (view instanceof CardView) { + ((CardView) view).setCardBackgroundColor(Color.WHITE); + } else { + view.setBackgroundResource(0); + } restoreColorScheme(); } else { if (selectedView != null) { - selectedView.setBackgroundResource(0); + if (selectedView instanceof CardView) { + ((CardView) selectedView).setCardBackgroundColor(Color.WHITE); + } else { + selectedView.setBackgroundResource(0); + } } selectedView = view; selectedPosition = position - 1; Log.d(TAG, "Position: " + selectedPosition); - view.setBackgroundColor(getResources().getColor(R.color.color_divider)); + if (view instanceof CardView) { + ((CardView) view).setCardBackgroundColor(Color.LTGRAY); + } else { + view.setBackgroundColor(ContextCompat.getColor(toolkit, R.color.color_divider)); + } changeColorScheme(); } return true; @@ -187,7 +278,7 @@ public boolean onItemLongClick(AdapterView parent, View view, int position, l /** * @brief Initialization function for setting up action bar */ - protected void setUpActionBar() { + private void setUpActionBar() { ActionBar actionBar = getSupportActionBar(); templateEdtiorList = (ListView) findViewById(R.id.template_editor_listview); if (actionBar == null) { @@ -200,7 +291,7 @@ protected void setUpActionBar() { /** * @brief Initialization function when the Temlpate Editor is created. */ - protected void setUpTemplateEditor() { + private void setUpTemplateEditor() { Template[] templates = Template.values(); template = templates[templateId]; @@ -209,6 +300,9 @@ protected void setUpTemplateEditor() { Object templateObject = templateClass.newInstance(); selectedTemplate = (TemplateInterface) templateObject; populateListView(selectedTemplate.newTemplateEditorAdapter(this)); + if (templateId == 5) { + populateMetaView(selectedTemplate.newMetaEditorAdapter(this)); + } setUpActionBar(); } catch (InstantiationException e) { e.printStackTrace(); @@ -220,7 +314,7 @@ protected void setUpTemplateEditor() { /** * @brief Initialization function when the Temlpate Editor is restored. */ - protected void restoreTemplateEditor(Bundle savedInstanceState) { + private void restoreTemplateEditor(Bundle savedInstanceState) { selectedTemplate = (TemplateInterface) savedInstanceState.getSerializable(Constants.TEMPLATE_OBJECT); oldFileName = savedInstanceState.getString(Constants.PROJECT_FILE_PATH); templateId = savedInstanceState.getInt(Constants.TEMPLATE_ID); @@ -230,6 +324,9 @@ protected void restoreTemplateEditor(Bundle savedInstanceState) { finish(); } else { populateListView(selectedTemplate.currentTemplateEditorAdapter()); + if (templateId == 5) { + populateMetaView(selectedTemplate.currentMetaEditorAdapter()); + } setUpActionBar(); } } @@ -248,6 +345,7 @@ public boolean onCreateOptionsMenu(Menu menu) { @Override public boolean onPrepareOptionsMenu(Menu menu) { Log.d(TAG, "onPrepareOptionsMenu"); + menu.clear(); if (showTemplateSelectedMenu) { getMenuInflater().inflate(R.menu.menu_template_item_selected, menu); } else { @@ -280,7 +378,8 @@ public boolean onOptionsItemSelected(MenuItem item) { @Override public void onClick(View v) { dialog.dismiss(); - selectedTemplate.deleteItem(selectedPosition); + selectedTemplate.deleteItem(TemplateEditor.this, selectedPosition); + selectedPosition = -1; restoreSelectedView(); } }); @@ -290,6 +389,7 @@ public void onClick(View v) { break; case R.id.action_edit: selectedTemplate.editItem(this, selectedPosition); + selectedPosition = -1; restoreSelectedView(); break; case R.id.action_save: @@ -327,7 +427,7 @@ public void onSuccess(final String path) { Uri fileUri = Uri.fromFile(new File(path)); try { - ArrayList uris = new ArrayList(); + ArrayList uris = new ArrayList<>(); Intent sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); sendIntent.setType("application/vnd.android.package-archive"); uris.add(fileUri); @@ -337,7 +437,7 @@ public void onSuccess(final String path) { } catch (Exception e) { - ArrayList uris = new ArrayList(); + ArrayList uris = new ArrayList<>(); Intent sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); sendIntent.setType("application/zip"); uris.add(fileUri); @@ -352,7 +452,9 @@ public void onFail(Exception e) { if (e != null) { e.printStackTrace(); mApkGenerationDialog.dismiss(); - Toast.makeText(TemplateEditor.this, "Build unsuccessful", Toast.LENGTH_SHORT).show(); + Message message = handlerToast.obtainMessage(); + message.arg1 = -1; + handlerToast.sendMessage(message); } } }); @@ -403,7 +505,9 @@ public void onFail(Exception e) { if (e != null) { e.printStackTrace(); mApkGenerationDialog.dismiss(); - Toast.makeText(TemplateEditor.this, "Build unsuccessful", Toast.LENGTH_SHORT).show(); + Message message = handlerToast.obtainMessage(); + message.arg1 = -1; + handlerToast.sendMessage(message); } } }); @@ -419,6 +523,8 @@ public void onFail(Exception e) { case android.R.id.home: onBackPressed(); break; + default: //do nothing + break; } return true; } @@ -428,7 +534,11 @@ public void onFail(Exception e) { */ public void restoreSelectedView() { if (selectedView != null) { + if (selectedView instanceof CardView) { + ((CardView) selectedView).setCardBackgroundColor(Color.WHITE); + } else { selectedView.setBackgroundResource(0); + } } restoreColorScheme(); @@ -439,9 +549,9 @@ public void restoreSelectedView() { *

* Edit mode is triggered, when the list item is long pressed. */ - public void changeColorScheme() { - int primaryColor = getResources().getColor(R.color.color_primary_dark); - int primaryColorDark = getResources().getColor(R.color.color_selected_dark); + private void changeColorScheme() { + int primaryColor = ContextCompat.getColor(toolkit, R.color.color_primary_dark); + int primaryColorDark = ContextCompat.getColor(toolkit, R.color.color_selected_dark); getSupportActionBar().setBackgroundDrawable(new ColorDrawable(primaryColor)); ThemeSingleton.get().positiveColor = ColorStateList.valueOf(primaryColor); ThemeSingleton.get().neutralColor = ColorStateList.valueOf(primaryColor); @@ -461,9 +571,9 @@ public void changeColorScheme() { *

* Edit mode is triggered, when the list item is long pressed. */ - public void restoreColorScheme() { - int primaryColor = getResources().getColor(R.color.color_primary); - int primaryColorDark = getResources().getColor(R.color.color_primary_dark); + private void restoreColorScheme() { + int primaryColor = ContextCompat.getColor(toolkit, R.color.color_primary); + int primaryColorDark = ContextCompat.getColor(toolkit, R.color.color_primary_dark); getSupportActionBar().setBackgroundDrawable(new ColorDrawable(primaryColor)); ThemeSingleton.get().positiveColor = ColorStateList.valueOf(primaryColor); ThemeSingleton.get().neutralColor = ColorStateList.valueOf(primaryColor); @@ -484,15 +594,19 @@ public void restoreColorScheme() { * @return Absolute path of the saved file. Null if there is some error. * @brief Saves the current project into a .buildmlearn file. */ - protected String saveProject() { + private String saveProject() { - EditText authorEditText = ((EditText) findViewById(R.id.author_name)); - EditText titleEditText = ((EditText) findViewById(R.id.template_title)); + EditText authorEditText = (EditText) findViewById(R.id.author_name); + EditText titleEditText = (EditText) findViewById(R.id.template_title); + assert findViewById(R.id.author_name) != null; String author = ((EditText) findViewById(R.id.author_name)).getText().toString(); + assert findViewById(R.id.template_title) != null; String title = ((EditText) findViewById(R.id.template_title)).getText().toString(); - if (author.equals("")) { + if ("".equals(author)) { + assert authorEditText != null; authorEditText.setError("Author name is required"); - } else if (title.equals("")) { + } else if ("".equals(title)) { + assert titleEditText != null; titleEditText.setError("Title is required"); } else { @@ -522,7 +636,7 @@ protected String saveProject() { doc.appendChild(rootElement); Element dataElement = doc.createElement("data"); rootElement.appendChild(dataElement); - if (selectedTemplate.getItems(doc).size() == 0) { + if (selectedTemplate.getItems(doc).size() == 0 || (selectedTemplate.getItems(doc).size() < 2 && templateId == 5)) { Toast.makeText(this, "Unable to perform action: No Data", Toast.LENGTH_SHORT).show(); return null; } @@ -553,7 +667,7 @@ protected String saveProject() { *

* Start the simulator with the fragment returned by the selected template. Simulator is started as a new activity. */ - protected void startSimulator() { + private void startSimulator() { String filePath = saveProject(); if (filePath == null || filePath.equals("")) { Toast.makeText(this, "Build unsuccessful", Toast.LENGTH_SHORT).show(); @@ -573,7 +687,7 @@ protected void startSimulator() { * This function is used in loading existing files to editor. Reads file at a given path, parse the * file and convert into and convert it into TemplateInterface object. */ - protected void parseSavedFile(String path) { + private void parseSavedFile(String path) { try { File fXmlFile = new File(path); @@ -603,13 +717,14 @@ protected void parseSavedFile(String path) { Object templateObject = templateClass.newInstance(); selectedTemplate = (TemplateInterface) templateObject; populateListView(selectedTemplate.loadProjectTemplateEditor(this, items)); + if (templateId == 5) { + populateMetaView(selectedTemplate.loadProjectMetaEditor(this, doc)); + } setUpActionBar(); updateHeaderDetails(name, title); - } catch (SAXException | IOException | ParserConfigurationException | IllegalAccessException e) { - e.printStackTrace(); - } catch (InstantiationException e) { + } catch (SAXException | IOException | ParserConfigurationException | IllegalAccessException | InstantiationException e) { e.printStackTrace(); } @@ -621,10 +736,12 @@ protected void parseSavedFile(String path) { * @param title Title of the template app * @brief Updates the title and author name in the header view. */ - protected void updateHeaderDetails(String name, String title) { - EditText authorEditText = ((EditText) findViewById(R.id.author_name)); - EditText titleEditText = ((EditText) findViewById(R.id.template_title)); + private void updateHeaderDetails(String name, String title) { + EditText authorEditText = (EditText) findViewById(R.id.author_name); + EditText titleEditText = (EditText) findViewById(R.id.template_title); + assert authorEditText != null; authorEditText.setText(name); + assert titleEditText != null; titleEditText.setText(title); } @@ -632,25 +749,16 @@ protected void updateHeaderDetails(String name, String title) { * @param adapter * @brief Sets the adapter to the ListView */ - protected void setAdapter(BaseAdapter adapter) { + private void setAdapter(BaseAdapter adapter) { templateEdtiorList.setAdapter(adapter); - setEmptyView(); } /** - * @brief Toggles the visibility of empty text if adapter has zero elements + * @param adapter + * @brief Sets the adapter to the ListView */ - protected void setEmptyView() { - - if (templateEdtiorList.getAdapter().getCount() == 1) { - findViewById(R.id.empty).setVisibility(View.VISIBLE); - } else { - findViewById(R.id.empty).setVisibility(View.GONE); - } + private void setAdapterMeta(BaseAdapter adapter) { + templateMetaList.setAdapter(adapter); } - - private void hideEmptyView() { - findViewById(R.id.empty).setVisibility(View.GONE); - } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TutorialActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TutorialActivity.java index 8b66a98d..681ef389 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TutorialActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/TutorialActivity.java @@ -15,11 +15,6 @@ */ public class TutorialActivity extends AppCompatActivity { - private static final String TAG = "Tutorial Activity"; - private TutorialAdapter mAdapter; - private ViewPager mPager; - private CirclePageIndicator mIndicator; - /** * {@inheritDoc} */ @@ -28,15 +23,15 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_tutorial); - mAdapter = new TutorialAdapter(this, getIntent().getBooleanExtra(Constants.START_ACTIVITY, false)); + TutorialAdapter mAdapter = new TutorialAdapter(this, getIntent().getBooleanExtra(Constants.START_ACTIVITY, false)); - mPager = (ViewPager) findViewById(R.id.pager); + ViewPager mPager = (ViewPager) findViewById(R.id.pager); // mPager.setAdapter(mAdapter); mPager.setAdapter(mAdapter); - mIndicator = (CirclePageIndicator) findViewById(R.id.indicator); + CirclePageIndicator mIndicator = (CirclePageIndicator) findViewById(R.id.indicator); mIndicator.setViewPager(mPager); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/NavigationDrawerMenuAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/NavigationDrawerMenuAdapter.java index 0da7b4b2..0a0a551a 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/NavigationDrawerMenuAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/NavigationDrawerMenuAdapter.java @@ -6,6 +6,7 @@ import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Build; +import android.support.v4.content.ContextCompat; import android.text.SpannableString; import android.text.Spanned; import android.text.style.ForegroundColorSpan; @@ -25,11 +26,11 @@ */ public class NavigationDrawerMenuAdapter extends BaseAdapter { - private Section[] sections = Section.values(); - private LayoutInflater inflater; + private final Section[] sections = Section.values(); + private final LayoutInflater inflater; + private final Context context; private int currentSectionForegroundColor; private int currentSectionBackgroundColor; - private Context context; public NavigationDrawerMenuAdapter(Context context, LayoutInflater inflater) { this.inflater = inflater; @@ -37,11 +38,11 @@ public NavigationDrawerMenuAdapter(Context context, LayoutInflater inflater) { // Select the primary color to tint the current section TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{R.attr.colorPrimary}); try { - currentSectionForegroundColor = a.getColor(0, context.getResources().getColor(R.color.color_primary)); + currentSectionForegroundColor = a.getColor(0, ContextCompat.getColor(context, R.color.color_primary)); } finally { a.recycle(); } - currentSectionBackgroundColor = context.getResources().getColor(R.color.translucent_grey); + currentSectionBackgroundColor = ContextCompat.getColor(context, R.color.translucent_grey); } /** @@ -82,7 +83,7 @@ public View getView(int position, View convertView, ViewGroup parent) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { sectionIcon = context.getDrawable(menu.getIconResId()); } else { - sectionIcon = context.getResources().getDrawable(menu.getIconResId()); + sectionIcon = ContextCompat.getDrawable(context, menu.getIconResId()); } int backgroundColor; if (menu.isSelected()) { @@ -90,6 +91,7 @@ public View getView(int position, View convertView, ViewGroup parent) { // sectionTitle.setSpan(new StyleSpan(Typeface.BOLD), 0, sectionTitle.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); sectionTitle.setSpan(new ForegroundColorSpan(currentSectionForegroundColor), 0, sectionTitle.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // We need to mutate the drawable before applying the ColorFilter, or else all the similar drawable instances will be tinted. + assert sectionIcon != null; sectionIcon.mutate().setColorFilter(currentSectionForegroundColor, PorterDuff.Mode.SRC_IN); backgroundColor = currentSectionBackgroundColor; } else { @@ -98,10 +100,8 @@ public View getView(int position, View convertView, ViewGroup parent) { tv.setText(sectionTitle); tv.setCompoundDrawablesWithIntrinsicBounds(sectionIcon, null, null, null); tv.setBackgroundColor(backgroundColor); - } else if (menu.getType() == Section.SECTION_DIVIDER) { - if (convertView == null) { + } else if (menu.getType() == Section.SECTION_DIVIDER && convertView == null) { convertView = inflater.inflate(R.layout.item_section_divider, parent, false); - } } return convertView; } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/SavedProjectAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/SavedProjectAdapter.java index db8f5dc6..71e401d3 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/SavedProjectAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/SavedProjectAdapter.java @@ -20,8 +20,8 @@ */ public class SavedProjectAdapter extends BaseAdapter { - private Context mContext; - private ArrayList data; + private final Context mContext; + private final ArrayList data; public SavedProjectAdapter(Context mContext, ArrayList data) { this.mContext = mContext; @@ -79,8 +79,8 @@ public View getView(int position, View convertView, ViewGroup parent) { } public class ProjectHolder { - TextViewPlus projectName; - TextViewPlus projectIcon; - TextViewPlus details; + public TextViewPlus projectName; + public TextViewPlus projectIcon; + public TextViewPlus details; } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TemplateAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TemplateAdapter.java index deb7ac78..4b735321 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TemplateAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TemplateAdapter.java @@ -21,15 +21,13 @@ */ public class TemplateAdapter extends BaseAdapter { - private Context context; - private int count; + private final Context context; - private Template[] templates = Template.values(); - private ListColor[] colors = ListColor.values(); + private final Template[] templates = Template.values(); + private final ListColor[] colors = ListColor.values(); - public TemplateAdapter(Context context, int count) { + public TemplateAdapter(Context context) { this.context = context; - this.count = count; } /** @@ -87,10 +85,13 @@ private enum ListColor { BLUE("#29A6D4"), GREEN("#1C7D6C"), ORANGE("#F77400"), - RED("#F53B3C"); + RED("#F53B3C"), + GRAYISH("#78909C"), + PURPLE("#AB47BC"); private @ColorRes + final int color; ListColor(String colorCode) { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TutorialAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TutorialAdapter.java index 9a8f1457..e65421a6 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TutorialAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TutorialAdapter.java @@ -23,10 +23,10 @@ */ public class TutorialAdapter extends PagerAdapter { - private Activity mActivity; - private Tutorial[] mTutorials; - private ListColor[] colors = ListColor.values(); - private boolean mStartActivity; + private final Activity mActivity; + private final Tutorial[] mTutorials; + private final ListColor[] colors = ListColor.values(); + private final boolean mStartActivity; public TutorialAdapter(Activity activity, boolean startActivity) { mActivity = activity; @@ -43,7 +43,7 @@ public int getCount() { } - public Tutorial getItem(int position) { + private Tutorial getItem(int position) { return mTutorials[position]; } @@ -103,7 +103,7 @@ public void onClick(View v) { */ @Override public boolean isViewFromObject(View view, Object object) { - return view == ((View) object); + return view == object; } /** @@ -122,6 +122,7 @@ private enum ListColor { private @ColorRes + final int color; ListColor(String colorCode) { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/Constants.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/Constants.java new file mode 100644 index 00000000..6b156df5 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/Constants.java @@ -0,0 +1,21 @@ +package org.buildmlearn.toolkit.comprehensiontemplate; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ +public class Constants { + public static final String firstrun = "firstRun"; + public static final int COL_TITLE = 1; + public static final int COL_PASSAGE = 2; + public static final int COL_TIME = 3; + public static final int COL_QUESTION = 1; + public static final int COL_OPTION_1 = 2; + public static final int COL_OPTION_2 = 3; + public static final int COL_OPTION_3 = 4; + public static final int COL_OPTION_4 = 5; + public static final int COL_CORRECT_ANSWER = 6; + public static final int COL_ANSWERED = 7; + public static final int COL_ATTEMPTED = 8; + public static String XMLFileName = "comprehension_content.xml"; + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionContract.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionContract.java new file mode 100644 index 00000000..9544b5a8 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionContract.java @@ -0,0 +1,35 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.data; + +import android.provider.BaseColumns; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ + +class ComprehensionContract { + + public static final class Questions implements BaseColumns { + + public static final String TABLE_NAME = "questions"; + + public static final String QUESTION = "question"; + public static final String OPTION_1 = "option_1"; + public static final String OPTION_2 = "option_2"; + public static final String OPTION_3 = "option_3"; + public static final String OPTION_4 = "option_4"; + public static final String CORRECT_ANSWER = "correct_answer"; + public static final String ANSWERED = "answered"; + public static final String ATTEMPTED = "attempted"; + + } + + public static final class MetaDetails implements BaseColumns { + + public static final String TABLE_NAME = "meta_details"; + + public static final String TITLE = "title"; + public static final String PASSAGE = "passage"; + public static final String TIME = "time"; + + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionDBHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionDBHelper.java new file mode 100644 index 00000000..3817db31 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionDBHelper.java @@ -0,0 +1,53 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionContract.MetaDetails; +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionContract.Questions; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ + +class ComprehensionDBHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "comprehension.db"; + private static final int DATABASE_VERSION = 1; + + public ComprehensionDBHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + final String SQL_CREATE__TABLE_A = "CREATE TABLE " + Questions.TABLE_NAME + " (" + + Questions._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Questions.QUESTION + " TEXT," + + Questions.OPTION_1 + " TEXT," + + Questions.OPTION_2 + " TEXT," + + Questions.OPTION_3 + " TEXT," + + Questions.OPTION_4 + " TEXT," + + Questions.CORRECT_ANSWER + " INTEGER," + + Questions.ANSWERED + " INTEGER," + + Questions.ATTEMPTED + " INTEGER )"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE_A); + + final String SQL_CREATE__TABLE_B = "CREATE TABLE " + MetaDetails.TABLE_NAME + " (" + + MetaDetails._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + MetaDetails.TITLE + " TEXT," + + MetaDetails.PASSAGE + " TEXT," + + MetaDetails.TIME + " INTEGER )"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE_B); + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Questions.TABLE_NAME); + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + MetaDetails.TABLE_NAME); + onCreate(sqLiteDatabase); + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionDb.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionDb.java new file mode 100644 index 00000000..c990d908 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/ComprehensionDb.java @@ -0,0 +1,171 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.support.annotation.NonNull; + +import org.buildmlearn.toolkit.comprehensiontemplate.Constants; +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionContract.Questions; + +import java.util.Arrays; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ +public class ComprehensionDb { + + private static final String EQUAL = " == "; + private final ComprehensionDBHelper dbHelper; + private SQLiteDatabase db; + + public ComprehensionDb(Context context) { + dbHelper = new ComprehensionDBHelper(context); + } + + public void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public boolean isOpen() { + return db.isOpen(); + } + + public void close() { + dbHelper.close(); + } + + public Cursor getMetaCursor() { + + return db.query( + ComprehensionContract.MetaDetails.TABLE_NAME, + null, + null, + null, + null, + null, + null + ); + } + + public void markAnswered(int id, int answer) { + + ContentValues values = new ContentValues(); + values.put(Questions.ANSWERED, answer); + values.put(Questions.ATTEMPTED, 1); + + db.update(Questions.TABLE_NAME, values, Questions._ID + " = ?", + new String[]{String.valueOf(id)}); + + } + + public void deleteAll() { + db.delete(Questions.TABLE_NAME, null, null); + db.delete(ComprehensionContract.MetaDetails.TABLE_NAME, null, null); + db.execSQL("delete from sqlite_sequence where name='" + Questions.TABLE_NAME + "';"); + db.execSQL("delete from sqlite_sequence where name='" + ComprehensionContract.MetaDetails.TABLE_NAME + "';"); + } + + public void markUnAnswered(int id) { + + ContentValues values = new ContentValues(); + values.put(Questions.ANSWERED, ""); + values.put(Questions.ATTEMPTED, 0); + + db.update(Questions.TABLE_NAME, values, Questions._ID + " = ?", + new String[]{String.valueOf(id)}); + + } + + public void resetCount() { + for (int i = 1; i <= getCountQuestions(); i++) { + markUnAnswered(i); + } + } + + public int[] getStatistics() { + int stat[] = new int[3]; + Arrays.fill(stat, 0); + + for (int i = 1; i <= getCountQuestions(); i++) { + Cursor cursor = getQuestionCursorById(i); + cursor.moveToFirst(); + + String correct_answer = cursor.getString(Constants.COL_CORRECT_ANSWER); + int attempted = cursor.getInt(Constants.COL_ATTEMPTED); + if (attempted == 1) { + String answer = cursor.getString(Constants.COL_ANSWERED); + if (answer.equals(correct_answer)) { + stat[0]++; + } else { + stat[1]++; + } + } else { + stat[2]++; + } + } + return stat; + } + + public Cursor getQuestionCursorById(int id) { + + String selection = Questions._ID + EQUAL + id; + + return db.query( + Questions.TABLE_NAME, + null, + selection, + null, + null, + null, + null + ); + } + + public long getCountQuestions() { + + return DatabaseUtils.queryNumEntries(db, + Questions.TABLE_NAME); + } + + public int bulkInsertQuestions(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(Questions.TABLE_NAME, null, value); + if (_id != -1) { + returnCount++; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + return returnCount; + } + + public int bulkInsertMetaDetails(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(ComprehensionContract.MetaDetails.TABLE_NAME, null, value); + if (_id != -1) { + returnCount++; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + return returnCount; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/DataUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/DataUtils.java new file mode 100644 index 00000000..e83a9702 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/DataUtils.java @@ -0,0 +1,46 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.data; + +import android.content.Context; + +import org.buildmlearn.toolkit.comprehensiontemplate.Constants; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ +public class DataUtils { + + public static String[] readTitleAuthor(Context myContext) { + String result[] = new String[2]; + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setValidating(false); + + DocumentBuilder db; + Document doc; + try { + File fXmlFile = new File(Constants.XMLFileName); + db = dbf.newDocumentBuilder(); + doc = db.parse(fXmlFile); + doc.normalize(); + + result[0] = doc.getElementsByTagName("title").item(0).getChildNodes() + .item(0).getNodeValue(); + + result[1] = doc.getElementsByTagName("name").item(0).getChildNodes() + .item(0).getNodeValue(); + + } catch (ParserConfigurationException | SAXException | IOException e) { + e.printStackTrace(); + } + return result; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/FetchXMLTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/FetchXMLTask.java new file mode 100644 index 00000000..d0063b50 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/data/FetchXMLTask.java @@ -0,0 +1,186 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.os.AsyncTask; + +import org.buildmlearn.toolkit.comprehensiontemplate.Constants; +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionContract.MetaDetails; +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionContract.Questions; +import org.buildmlearn.toolkit.templates.ComprehensionMetaModel; +import org.buildmlearn.toolkit.templates.ComprehensionModel; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Vector; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ +public class FetchXMLTask extends AsyncTask { + + private final Context mContext; + + public FetchXMLTask(Context context) { + mContext = context; + } + + private static String getValue(String tag, Element element) { + NodeList nodeList = null; + NodeList node1 = element.getElementsByTagName(tag); + if (node1 != null && node1.getLength() != 0) + nodeList = node1.item(0).getChildNodes(); + if (nodeList == null) + return ""; + else if (nodeList.getLength() == 0) + return ""; + else { + Node node = nodeList.item(0); + return node.getNodeValue(); + } + } + + private void saveMetaData(ComprehensionMetaModel metaDetails) { + + String title; + String passage; + long time; + + title = metaDetails.getTitle(); + passage = metaDetails.getPassage(); + time = metaDetails.getTime(); + + ContentValues quesValues = new ContentValues(); + + quesValues.put(MetaDetails.TITLE, title); + quesValues.put(MetaDetails.PASSAGE, passage); + quesValues.put(MetaDetails.TIME, time); + + ComprehensionDb db = new ComprehensionDb(mContext); + db.open(); + db.bulkInsertMetaDetails(new ContentValues[]{quesValues}); + db.close(); + } + + private void saveQuestions(ArrayList questions) { + + Vector cVVector = new Vector<>(questions.size()); + + for (int i = 0; i < questions.size(); i++) { + + String question; + ArrayList options; + int correctAnswer; + + ComprehensionModel questionInfo = questions.get(i); + + question = questionInfo.getQuestion(); + options = questionInfo.getOptions(); + correctAnswer = questionInfo.getCorrectAnswer(); + + ContentValues quesValues = new ContentValues(); + + quesValues.put(Questions.QUESTION, question); + if (options.size() >= 1) { + quesValues.put(Questions.OPTION_1, options.get(0)); + } + if (options.size() >= 2) { + quesValues.put(Questions.OPTION_2, options.get(1)); + } + if (options.size() >= 3) { + quesValues.put(Questions.OPTION_3, options.get(2)); + } + if (options.size() >= 4) { + quesValues.put(Questions.OPTION_4, options.get(3)); + } + quesValues.put(Questions.CORRECT_ANSWER, correctAnswer); + quesValues.put(Questions.ATTEMPTED, 0); + + cVVector.add(quesValues); + } + // add to database + if (cVVector.size() > 0) { + ContentValues[] cvArray = new ContentValues[cVVector.size()]; + cVVector.toArray(cvArray); + ComprehensionDb db = new ComprehensionDb(mContext); + db.open(); + db.bulkInsertQuestions(cvArray); + db.close(); + } + } + + @Override + protected Void doInBackground(String... params) { + + if (params.length == 0) { + return null; + } + ArrayList mList; + ArrayList mOptions; + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setValidating(false); + + DocumentBuilder db; + Document doc; + try { + File fXmlFile = new File(Constants.XMLFileName); + db = dbf.newDocumentBuilder(); + doc = db.parse(fXmlFile); + doc.normalize(); + mList = new ArrayList<>(); + + String title = doc.getElementsByTagName(ComprehensionMetaModel.TITLE_TAG).item(0).getTextContent(); + String passage = doc.getElementsByTagName(ComprehensionMetaModel.PASSAGE_TAG).item(0).getTextContent(); + long timer = Long.parseLong(doc.getElementsByTagName(ComprehensionMetaModel.TIMER_TAG).item(0).getTextContent()); + + saveMetaData(new ComprehensionMetaModel(title, passage, timer)); + + NodeList childNodes = doc.getElementsByTagName("item"); + + for (int i = 0; i < childNodes.getLength(); i++) { + ComprehensionModel app = new ComprehensionModel(); + + Node child = childNodes.item(i); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element2 = (Element) child; + + app.setQuestion(getValue("question", element2)); + mOptions = new ArrayList<>(); + NodeList optionNodes = element2 + .getElementsByTagName("option"); + for (int j = 0; j < optionNodes.getLength(); j++) { + mOptions.add(optionNodes.item(j).getChildNodes().item(0).getNodeValue()); + } + app.setCorrectAnswer(Integer.parseInt(getValue("answer", element2))); + app.setOptions(mOptions); + } + mList.add(app); + } + saveQuestions(mList); + } catch (ParserConfigurationException e) { + return null; + } catch (FileNotFoundException e) { + return null; + } catch (SAXException e) { + return null; + } catch (IOException e) { + return null; + } + return null; + } + +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/LastFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/LastFragment.java new file mode 100644 index 00000000..6987b871 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/LastFragment.java @@ -0,0 +1,104 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.fragment; + +import android.app.FragmentManager; +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.comprehensiontemplate.Constants; +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionDb; + +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ +public class LastFragment extends Fragment { + + public static Fragment newInstance() { + return new LastFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.comprehension_fragment_last, container, false); + + final ComprehensionDb db = new ComprehensionDb(getActivity()); + db.open(); + + Cursor cursor = db.getMetaCursor(); + cursor.moveToFirst(); + + int stat[] = db.getStatistics(); + + Toolbar maintoolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + Cursor meta = db.getMetaCursor(); + meta.moveToFirst(); + String title = meta.getString(Constants.COL_TITLE); + maintoolbar.setTitle(title); + maintoolbar.inflateMenu(R.menu.menu_main_white); + + maintoolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.action_about: + AlertDialog.Builder builder = + new AlertDialog.Builder(getActivity()); + builder.setTitle(String.format("%1$s", getString(R.string.comprehension_about_us))); + builder.setMessage(getResources().getText(R.string.comprehension_about_text)); + builder.setPositiveButton("OK", null); + AlertDialog welcomeAlert = builder.create(); + welcomeAlert.show(); + assert welcomeAlert.findViewById(android.R.id.message) != null; + assert welcomeAlert.findViewById(android.R.id.message) != null; + ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + break; + default: //do nothing + break; + } + return true; + } + }); + + db.close(); + + ((TextView) rootView.findViewById(R.id.correct)).setText(String.format(Locale.getDefault(), "Total Correct : %1$d", stat[0])); + ((TextView) rootView.findViewById(R.id.wrong)).setText(String.format(Locale.getDefault(), "Total Wrong : %1$d", stat[1])); + ((TextView) rootView.findViewById(R.id.un_answered)).setText(String.format(Locale.getDefault(), "Total Unanswered : %1$d", stat[2])); + + rootView.findViewById(R.id.restart).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, "1"); + + Fragment frag = MainFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + } + }); + + rootView.findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().finish(); + } + }); + + + return rootView; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/MainFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/MainFragment.java new file mode 100644 index 00000000..16821273 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/MainFragment.java @@ -0,0 +1,182 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.fragment; + +import android.app.FragmentManager; +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.support.design.widget.NavigationView; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.comprehensiontemplate.Constants; +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionDb; + +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ +public class MainFragment extends Fragment implements NavigationView.OnNavigationItemSelectedListener { + + private View rootView; + private ComprehensionDb db; + + public static Fragment newInstance() { + return new MainFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + rootView = inflater.inflate(R.layout.comprehension_fragment_main, container, false); + Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar); + toolbar.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.colorPrimary_comprehension)); + toolbar.inflateMenu(R.menu.menu_main_white); + + toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.action_about: + AlertDialog.Builder builder = + new AlertDialog.Builder(getActivity()); + builder.setTitle(String.format("%1$s", getString(R.string.comprehension_about_us))); + builder.setMessage(getResources().getText(R.string.comprehension_about_text)); + builder.setPositiveButton("OK", null); + AlertDialog welcomeAlert = builder.create(); + welcomeAlert.show(); + assert welcomeAlert.findViewById(android.R.id.message) != null; + assert welcomeAlert.findViewById(android.R.id.message) != null; + ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + break; + default: //do nothing + break; + } + return true; + } + }); + + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( + getActivity(), drawer, toolbar, R.string.comprehension_navigation_drawer_open, R.string.comprehension_navigation_drawer_close); + drawer.addDrawerListener(toggle); + toggle.syncState(); + + NavigationView navigationView = (NavigationView) rootView.findViewById(R.id.nav_view); + navigationView.setNavigationItemSelectedListener(this); + + + db = new ComprehensionDb(getActivity()); + db.open(); + db.resetCount(); + + Cursor cursor = db.getMetaCursor(); + cursor.moveToFirst(); + String title = cursor.getString(Constants.COL_TITLE); + toolbar.setTitle(title); + String passage = cursor.getString(Constants.COL_PASSAGE); + final long time = cursor.getLong(Constants.COL_TIME); + final TextView timer = (TextView) rootView.findViewById(R.id.timer); + assert timer != null; + timer.setText(String.valueOf(time)); + + final CountDownTimer countDownTimer = new CountDownTimer(time * 1000, 1000) { + + public void onTick(long millisUntilFinished) { + long min = millisUntilFinished / 60000; + long sec = millisUntilFinished / 1000 - min * 60; + timer.setText(String.format(Locale.getDefault(), "%1$d:%2$02d", min, sec)); + } + + public void onFinish() { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, "1"); + + Fragment frag = QuestionFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + } + }.start(); + + Menu m = navigationView.getMenu(); + SubMenu topChannelMenu = m.addSubMenu("Questions"); + long numQues = db.getCountQuestions(); + + for (int i = 1; i <= numQues; i++) { + topChannelMenu.add(String.format(Locale.getDefault(), "Question %1$d", i)); + topChannelMenu.getItem(i - 1).setIcon(R.drawable.ic_assignment_black_24dp); + final int finalI = i; + topChannelMenu.getItem(i - 1).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(finalI)); + countDownTimer.cancel(); + Fragment frag = QuestionFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + return false; + } + }); + } + + MenuItem mi = m.getItem(m.size() - 1); + mi.setTitle(mi.getTitle()); + + ((TextView) rootView.findViewById(R.id.passage)).setText(passage); + rootView.findViewById(R.id.go_to_ques).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, "1"); + countDownTimer.cancel(); + Fragment frag = QuestionFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + + } + }); + + return rootView; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + db.close(); + ViewGroup mContainer = (ViewGroup) getActivity().findViewById(R.id.container); + mContainer.removeAllViews(); + } + + @Override + public boolean onNavigationItemSelected(MenuItem item) { + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + drawer.closeDrawer(GravityCompat.START); + return true; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/QuestionFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/QuestionFragment.java new file mode 100644 index 00000000..f0eeee6e --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/QuestionFragment.java @@ -0,0 +1,257 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.fragment; + +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.support.design.widget.NavigationView; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RadioGroup; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.comprehensiontemplate.Constants; +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionDb; + +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ +public class QuestionFragment extends Fragment + implements NavigationView.OnNavigationItemSelectedListener { + + private View rootView; + private ComprehensionDb db; + + public static Fragment newInstance() { + return new QuestionFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + rootView = inflater.inflate(R.layout.comprehension_fragment_question, container, false); + + Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar); + toolbar.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.colorPrimary_comprehension)); + toolbar.inflateMenu(R.menu.menu_main_white); + + toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.action_about: + AlertDialog.Builder builder = + new AlertDialog.Builder(getActivity()); + builder.setTitle(String.format("%1$s", getString(R.string.comprehension_about_us))); + builder.setMessage(getResources().getText(R.string.comprehension_about_text)); + builder.setPositiveButton("OK", null); + AlertDialog welcomeAlert = builder.create(); + welcomeAlert.show(); + assert welcomeAlert.findViewById(android.R.id.message) != null; + assert welcomeAlert.findViewById(android.R.id.message) != null; + ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + break; + default: //do nothing + break; + } + return true; + } + }); + + + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( + getActivity(), drawer, toolbar, R.string.comprehension_navigation_drawer_open, R.string.comprehension_navigation_drawer_close); + drawer.addDrawerListener(toggle); + toggle.syncState(); + + NavigationView navigationView = (NavigationView) rootView.findViewById(R.id.nav_view); + navigationView.setNavigationItemSelectedListener(this); + + Bundle arguments = getArguments(); + String questionId = null; + if (arguments != null) { + questionId = arguments.getString(Intent.EXTRA_TEXT); + } + + db = new ComprehensionDb(getActivity()); + db.open(); + Cursor cursor = db.getQuestionCursorById(Integer.parseInt(questionId)); + cursor.moveToFirst(); + String question = cursor.getString(Constants.COL_QUESTION); + String option_1 = cursor.getString(Constants.COL_OPTION_1); + String option_2 = cursor.getString(Constants.COL_OPTION_2); + String option_3 = cursor.getString(Constants.COL_OPTION_3); + String option_4 = cursor.getString(Constants.COL_OPTION_4); + int attempted = cursor.getInt(Constants.COL_ATTEMPTED); + String answered; + + Cursor meta = db.getMetaCursor(); + meta.moveToFirst(); + String title = meta.getString(Constants.COL_TITLE); + toolbar.setTitle(title); + + Menu m = navigationView.getMenu(); + SubMenu topChannelMenu = m.addSubMenu("Questions"); + long numQues = db.getCountQuestions(); + + final String finalQuestionId = questionId; + + final RadioGroup rg = (RadioGroup) rootView.findViewById(R.id.radio_group); + + if (attempted == 1) { + answered = cursor.getString(Constants.COL_ANSWERED); + rg.check(rg.getChildAt(Integer.parseInt(answered)).getId()); + } + for (int i = 1; i <= numQues; i++) { + topChannelMenu.add(String.format(Locale.getDefault(), "Question %1$d", i)); + topChannelMenu.getItem(i - 1).setIcon(R.drawable.ic_assignment_black_24dp); + final int finalI = i; + topChannelMenu.getItem(i - 1).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + int radioButtonID = rg.getCheckedRadioButtonId(); + View radioButton = rg.findViewById(radioButtonID); + int idx = rg.indexOfChild(radioButton); + + if (idx == -1) { + db.markUnAnswered(Integer.parseInt(finalQuestionId)); + } else { + db.markAnswered(Integer.parseInt(finalQuestionId), idx); + } + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(finalI)); + + Fragment frag = QuestionFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + + return false; + } + }); + } + + ((TextView) rootView.findViewById(R.id.question_title)).setText(String.format(Locale.getDefault(), "Question No : %1$s", questionId)); + ((TextView) rootView.findViewById(R.id.question)).setText(question); + if (option_1 != null) { + rootView.findViewById(R.id.radioButton1).setVisibility(View.VISIBLE); + ((TextView) rootView.findViewById(R.id.radioButton1)).setText(option_1); + } + if (option_2 != null) { + rootView.findViewById(R.id.radioButton2).setVisibility(View.VISIBLE); + ((TextView) rootView.findViewById(R.id.radioButton2)).setText(option_2); + } + if (option_3 != null) { + rootView.findViewById(R.id.radioButton3).setVisibility(View.VISIBLE); + ((TextView) rootView.findViewById(R.id.radioButton3)).setText(option_3); + } + if (option_4 != null) { + rootView.findViewById(R.id.radioButton4).setVisibility(View.VISIBLE); + ((TextView) rootView.findViewById(R.id.radioButton4)).setText(option_4); + } + + + rootView.findViewById(R.id.next).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + int radioButtonID = rg.getCheckedRadioButtonId(); + View radioButton = rg.findViewById(radioButtonID); + int idx = rg.indexOfChild(radioButton); + + if (idx == -1) { + db.markUnAnswered(Integer.parseInt(finalQuestionId)); + } else { + db.markAnswered(Integer.parseInt(finalQuestionId), idx); + } + + long numColumns = db.getCountQuestions(); + + long nextQuesId = Integer.parseInt(finalQuestionId) + 1; + + if (nextQuesId <= numColumns) { + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(nextQuesId)); + + Fragment frag = QuestionFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + + } else { + + Fragment frag = LastFragment.newInstance(); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + + } + + } + }); + + if (Integer.parseInt(questionId) == 1) { + + rootView.findViewById(R.id.previous).setVisibility(View.INVISIBLE); + + } else { + + rootView.findViewById(R.id.previous).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + int radioButtonID = rg.getCheckedRadioButtonId(); + View radioButton = rg.findViewById(radioButtonID); + int idx = rg.indexOfChild(radioButton); + + if (idx == -1) { + db.markUnAnswered(Integer.parseInt(finalQuestionId)); + } else { + db.markAnswered(Integer.parseInt(finalQuestionId), idx); + } + + int prevQuesId = Integer.parseInt(finalQuestionId) - 1; + + if (prevQuesId >= 1) { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(prevQuesId)); + + Fragment frag = QuestionFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + + } + } + }); + } + return rootView; + } + + @Override + public boolean onNavigationItemSelected(MenuItem item) { + + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + drawer.closeDrawer(GravityCompat.START); + return true; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + db.close(); + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/SplashFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/SplashFragment.java new file mode 100644 index 00000000..1b370bbd --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/comprehensiontemplate/fragment/SplashFragment.java @@ -0,0 +1,65 @@ +package org.buildmlearn.toolkit.comprehensiontemplate.fragment; + +import android.app.Activity; +import android.app.FragmentManager; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.comprehensiontemplate.Constants; +import org.buildmlearn.toolkit.comprehensiontemplate.data.ComprehensionDb; +import org.buildmlearn.toolkit.comprehensiontemplate.data.DataUtils; +import org.buildmlearn.toolkit.comprehensiontemplate.data.FetchXMLTask; +import org.buildmlearn.toolkit.views.TextViewPlus; + +/** + * Created by Anupam (opticod) on 5/6/16. + */ +public class SplashFragment extends Fragment { + + public static Fragment newInstance(String path) { + SplashFragment fragment = new SplashFragment(); + Constants.XMLFileName = path; + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_splash, container, false); + + final Activity mActivity = getActivity(); + final String result[] = DataUtils.readTitleAuthor(getContext()); + TextView title = (TextView) rootView.findViewById(R.id.title); + TextView author_name = (TextView) rootView.findViewById(R.id.author_name); + + title.setText(result[0]); + author_name.setText(result[1]); + ((TextViewPlus) rootView.findViewById(R.id.intro_text)).setText(getResources().getString(R.string.comprehension_title)); + + + rootView.findViewById(R.id.enter).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), MainFragment.newInstance()).addToBackStack(null).commit(); + } + }); + + ComprehensionDb db = new ComprehensionDb(mActivity); + db.open(); + db.deleteAll(); + + long numColumns = db.getCountQuestions(); + db.close(); + if (numColumns == 0) { + FetchXMLTask xmlTask = new FetchXMLTask(getActivity()); + xmlTask.execute(Constants.XMLFileName); + } + return rootView; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/FlashModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/FlashModel.java index c3201324..234fd883 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/FlashModel.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/FlashModel.java @@ -4,8 +4,11 @@ /** * @brief Simulator code for Flash Card Template */ -public class FlashModel { - String question, answer, hint, base64; +class FlashModel { + private String question; + private String answer; + private String hint; + private String base64; public String getQuestion() { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/GlobalData.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/GlobalData.java index 1fcb75d2..58803a02 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/GlobalData.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/GlobalData.java @@ -42,7 +42,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; @@ -57,18 +56,15 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ public class GlobalData { private static GlobalData instance = null; + private final List iQuizList = new ArrayList<>(); String iQuizTitle = null; String iQuizAuthor = null; int totalCards = 0; - - BufferedReader br; - List iQuizList = new ArrayList(); - ArrayList model = null; - int iSelectedIndex = -1; + private BufferedReader br; - protected GlobalData() { + private GlobalData() { // Exists only to defeat instantiation. } @@ -89,7 +85,7 @@ private static String getValue(String tag, Element element) { else if (nodeList.getLength() == 0) return ""; else { - Node node = (Node) nodeList.item(0); + Node node = nodeList.item(0); return node.getNodeValue(); } @@ -136,10 +132,10 @@ public void readXmlContent(Context myContext, String fileName) { FlashModel app = null; while (eventType != XmlPullParser.END_DOCUMENT) { - String name = null; + String name; switch (eventType) { case XmlPullParser.START_DOCUMENT: - model = new ArrayList(); + model = new ArrayList<>(); break; case XmlPullParser.START_TAG: name = parser.getName(); @@ -172,10 +168,8 @@ public void readXmlContent(Context myContext, String fileName) { eventType = parser.next(); } - } catch (XmlPullParserException e1) { + } catch (XmlPullParserException | IOException e1) { e1.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); } } @@ -190,7 +184,7 @@ public void readXml(String filePath) { try { - model = new ArrayList(); + model = new ArrayList<>(); File fXmlFile = new File(filePath); db = dbf.newDocumentBuilder(); doc = db.parse(fXmlFile); @@ -206,7 +200,6 @@ public void readXml(String filePath) { // NamedNodeMap node1 = author_nodes.item(0).getAttributes(); iQuizAuthor = doc.getElementsByTagName("name").item(0) .getChildNodes().item(0).getNodeValue(); - ; // node1.getNamedItem("name").getNodeValue(); NodeList childNodes = doc.getElementsByTagName("item"); // Log.e("tag", "childNodes" + childNodes.getLength()); @@ -230,18 +223,12 @@ public void readXml(String filePath) { totalCards = model.size(); Log.d("tag", "totalCards" + totalCards); - } catch (ParserConfigurationException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } catch (FileNotFoundException e) { + } catch (ParserConfigurationException | IOException e) { Log.e("tag", e.getLocalizedMessage()); e.printStackTrace(); } catch (SAXException e) { Log.e("tag", e.getLocalizedMessage()); e.printStackTrace(); - } catch (IOException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/MainFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/MainFragment.java index d65762a4..f19d5ad8 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/MainFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/MainFragment.java @@ -1,10 +1,10 @@ package org.buildmlearn.toolkit.flashcardtemplate; -import android.app.Fragment; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.util.Base64; import android.view.Gravity; import android.view.LayoutInflater; @@ -26,17 +26,17 @@ */ public class MainFragment extends Fragment implements AnimationListener { - View answerView, questionView; - Button flipButton; - Button preButton; - Button nextButton; - boolean isFlipped = false; - int iQuestionIndex = 0; - GlobalData gd = GlobalData.getInstance(); - String flashCardanswer; - ImageView questionImage; - TextView flashcardNumber; - TextView questionText, hintText; + private final GlobalData gd = GlobalData.getInstance(); + private View answerView; + private View questionView; + private Button preButton; + private boolean isFlipped = false; + private int iQuestionIndex = 0; + private String flashCardanswer; + private ImageView questionImage; + private TextView flashcardNumber; + private TextView questionText; + private TextView hintText; private Animation animation1; private Animation animation2; private View currentView; @@ -65,9 +65,9 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa hintText = (TextView) view.findViewById(R.id.questionhint); flashcardNumber = (TextView) view.findViewById(R.id.flashCardNumber); - flipButton = (Button) view.findViewById(R.id.flip_button); + Button flipButton = (Button) view.findViewById(R.id.flip_button); preButton = (Button) view.findViewById(R.id.pre_button); - nextButton = (Button) view.findViewById(R.id.next_button); + Button nextButton = (Button) view.findViewById(R.id.next_button); populateQuestion(iQuestionIndex); currentView = questionView; @@ -117,7 +117,7 @@ public void onClick(View v) { } else { - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new ScoreFragment()).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new ScoreFragment()).addToBackStack(null).commit(); reInitialize(); } @@ -128,7 +128,7 @@ public void onClick(View v) { } - public void populateQuestion(int index) { + private void populateQuestion(int index) { if (index == 0) { preButton.setEnabled(false); @@ -159,7 +159,7 @@ public void populateQuestion(int index) { } - public void reInitialize() { + private void reInitialize() { iQuestionIndex = 0; gd.model.clear(); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/ScoreFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/ScoreFragment.java index bcf92b6d..63d59821 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/ScoreFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/ScoreFragment.java @@ -1,8 +1,8 @@ package org.buildmlearn.toolkit.flashcardtemplate; -import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -18,7 +18,6 @@ * @brief Simulator code for Flash Card Template */ public class ScoreFragment extends Fragment { - GlobalData gd; @Nullable @@ -26,7 +25,7 @@ public class ScoreFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.flash_simu_finish, container, false); - gd = GlobalData.getInstance(); + GlobalData gd = GlobalData.getInstance(); TextView mCardQuizName = (TextView) view.findViewById(R.id.tv_lastcard); mCardQuizName.setText(gd.iQuizTitle); @@ -36,7 +35,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa @Override public void onClick(View arg0) { - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, StartFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), StartFragment.TAG).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, StartFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), StartFragment.TAG).addToBackStack(null).commit(); //t } }); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/StartFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/StartFragment.java index 7de469c0..b8fcfc9a 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/StartFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/StartFragment.java @@ -1,8 +1,8 @@ package org.buildmlearn.toolkit.flashcardtemplate; -import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -21,8 +21,6 @@ public class StartFragment extends Fragment { public static final String TAG = "Start Fragment"; - GlobalData gd; - public static Fragment newInstance(String path) { StartFragment fragment = new StartFragment(); Bundle bundle = new Bundle(); @@ -38,7 +36,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa View view = inflater.inflate(R.layout.flash_simu_start_view, container, false); - gd = GlobalData.getInstance(); + GlobalData gd = GlobalData.getInstance(); gd.readXml(getArguments().getString(Constants.SIMULATOR_FILE_PATH)); TextView quizAuthor = (TextView) view.findViewById(R.id.tv_author); @@ -52,7 +50,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa @Override public void onClick(View arg0) { - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new MainFragment()).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new MainFragment()).addToBackStack(null).commit(); } }); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/HomeFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/HomeFragment.java index e9e8c78c..f3029a70 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/HomeFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/HomeFragment.java @@ -1,6 +1,5 @@ package org.buildmlearn.toolkit.fragment; -import android.app.Activity; import android.app.Fragment; import android.content.Intent; import android.os.Bundle; @@ -16,18 +15,6 @@ */ public class HomeFragment extends Fragment { - - public HomeFragment() { - // Required empty public constructor - } - /** - * @copydoc android.app.Fragment.onCreate(Bundle savedInstanceState) - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - } /** * {@inheritDoc} */ @@ -44,13 +31,6 @@ public void onClick(View view) { }); return view; } - /** - * {@inheritDoc} - */ - @Override - public void onDetach() { - super.onDetach(); - } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadProjectFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadProjectFragment.java index 1ea91834..5966ee70 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadProjectFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadProjectFragment.java @@ -1,16 +1,28 @@ package org.buildmlearn.toolkit.fragment; +import android.app.Activity; import android.app.Fragment; import android.content.Intent; +import android.content.res.ColorStateList; +import android.graphics.drawable.ColorDrawable; +import android.os.Build; import android.os.Bundle; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.Toast; +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import com.afollestad.materialdialogs.internal.ThemeSingleton; + import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.ToolkitApplication; import org.buildmlearn.toolkit.activity.TemplateEditor; @@ -40,9 +52,14 @@ public class LoadProjectFragment extends Fragment implements AbsListView.OnItemC private static final String TAG = "Load Project Fragment"; private AbsListView mListView; + private boolean showTemplateSelectedMenu; private SavedProjectAdapter mAdapter; private ToolkitApplication mToolkit; + private Activity activity; private ArrayList savedProjects; + private View selectedView = null; + + private int selectedPosition = -1; /** * {@inheritDoc} @@ -50,8 +67,9 @@ public class LoadProjectFragment extends Fragment implements AbsListView.OnItemC @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + setHasOptionsMenu(true); mToolkit = (ToolkitApplication) getActivity().getApplicationContext(); + activity = getActivity(); savedProjects = new ArrayList<>(); String path = mToolkit.getSavedDir(); @@ -65,10 +83,10 @@ public void onCreate(Bundle savedInstanceState) { } Log.d("Files", "Size: " + file.length); - for (int i = 0; i < file.length; i++) { + for (File aFile : file) { - Log.d(TAG, file[i].getAbsolutePath()); - File fXmlFile = new File(file[i].getAbsolutePath()); + Log.d(TAG, aFile.getAbsolutePath()); + File fXmlFile = new File(aFile.getAbsolutePath()); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder; try { @@ -77,13 +95,7 @@ public void onCreate(Bundle savedInstanceState) { doc.getDocumentElement().normalize(); Log.d("Files", "Root element :" + doc.getDocumentElement().getAttribute("type")); savedProjects.add(new SavedProject(fXmlFile, fXmlFile.getName(), fXmlFile.lastModified(), doc.getDocumentElement().getAttribute("type"), fXmlFile.getAbsolutePath())); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (DOMException e) { + } catch (ParserConfigurationException | DOMException | IOException | SAXException e) { e.printStackTrace(); } } @@ -103,8 +115,7 @@ public int compare(SavedProject f1, SavedProject f2) { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_loadproject, container, false); - return view; + return inflater.inflate(R.layout.fragment_loadproject, container, false); } /** @@ -116,6 +127,26 @@ public void onViewCreated(View view, Bundle savedInstanceState) { mListView = (AbsListView) view.findViewById(android.R.id.list); setAdapter(mAdapter); mListView.setOnItemClickListener(this); + mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + if (selectedPosition == position) { + selectedPosition = -1; + view.setBackgroundResource(0); + restoreColorScheme(); + } else { + if (selectedView != null) { + selectedView.setBackgroundResource(0); + } + selectedView = view; + selectedPosition = position; + Log.d(TAG, "Position: " + selectedPosition); + view.setBackgroundColor(ContextCompat.getColor(mToolkit, R.color.color_divider)); + changeColorScheme(); + } + return true; + } + }); } /** @@ -172,8 +203,8 @@ public void onResume() { Log.d("Files", "Size: " + file.length); - for (int i = 0; i < file.length; i++) { - File fXmlFile = new File(file[i].getAbsolutePath()); + for (File aFile : file) { + File fXmlFile = new File(aFile.getAbsolutePath()); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder; try { @@ -182,13 +213,7 @@ public void onResume() { doc.getDocumentElement().normalize(); Log.d("Files", "Root element :" + doc.getDocumentElement().getAttribute("type")); savedProjects.add(new SavedProject(fXmlFile, fXmlFile.getName(), fXmlFile.lastModified(), doc.getDocumentElement().getAttribute("type"), fXmlFile.getAbsolutePath())); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (DOMException e) { + } catch (ParserConfigurationException | DOMException | IOException | SAXException e) { e.printStackTrace(); } } @@ -204,4 +229,118 @@ public int compare(SavedProject f1, SavedProject f2) { } super.onResume(); } + + /** + * @brief Restores the color scheme when switching from edit mode to normal mode. + *

+ * Edit mode is triggered, when the list item is long pressed. + */ + private void restoreColorScheme() { + int primaryColor = ContextCompat.getColor(mToolkit, R.color.color_primary); + int primaryColorDark = ContextCompat.getColor(mToolkit, R.color.color_primary_dark); + ((AppCompatActivity) activity).getSupportActionBar().setBackgroundDrawable(new ColorDrawable(primaryColor)); + ThemeSingleton.get().positiveColor = ColorStateList.valueOf(primaryColor); + ThemeSingleton.get().neutralColor = ColorStateList.valueOf(primaryColor); + ThemeSingleton.get().negativeColor = ColorStateList.valueOf(primaryColor); + ThemeSingleton.get().widgetColor = primaryColor; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + activity.getWindow().setStatusBarColor(primaryColorDark); + activity.getWindow().setNavigationBarColor(primaryColor); + } + showTemplateSelectedMenu = false; + activity.invalidateOptionsMenu(); + } + + /** + * @brief Changes the color scheme when switching from normal mode to edit mode. + *

+ * Edit mode is triggered, when the list item is long pressed. + */ + private void changeColorScheme() { + int primaryColor = ContextCompat.getColor(mToolkit, R.color.color_primary_dark); + int primaryColorDark = ContextCompat.getColor(mToolkit, R.color.color_selected_dark); + ((AppCompatActivity) activity).getSupportActionBar().setBackgroundDrawable(new ColorDrawable(primaryColor)); + ThemeSingleton.get().positiveColor = ColorStateList.valueOf(primaryColor); + ThemeSingleton.get().neutralColor = ColorStateList.valueOf(primaryColor); + ThemeSingleton.get().negativeColor = ColorStateList.valueOf(primaryColor); + ThemeSingleton.get().widgetColor = primaryColor; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + activity.getWindow().setStatusBarColor(primaryColorDark); + activity.getWindow().setNavigationBarColor(primaryColor); + } + + showTemplateSelectedMenu = true; + activity.invalidateOptionsMenu(); + } + + /** + * {@inheritDoc} + */ + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + if (showTemplateSelectedMenu) { + activity.getMenuInflater().inflate(R.menu.menu_project_selected, menu); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + switch (id) { + case R.id.action_delete: + + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.dialog_delete_title) + .content(R.string.dialog_delete_msg) + .positiveText(R.string.dialog_yes) + .negativeText(R.string.dialog_no) + .build(); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog.dismiss(); + deleteItem(selectedPosition); + restoreSelectedView(); + } + }); + dialog.show(); + break; + default: //do nothing + break; + } + return super.onOptionsItemSelected(item); + } + + /** + * @brief Removes selected project item + */ + private void deleteItem(int selectedPosition) { + SavedProject project = savedProjects.get(selectedPosition); + File file = new File(project.getFile().getPath()); + boolean deleted = file.delete(); + if (deleted) { + savedProjects.remove(selectedPosition); + mAdapter.notifyDataSetChanged(); + setEmptyText(); + Toast.makeText(activity, "Project Successfully Deleted!", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(activity, "Project Deletion Failed!", Toast.LENGTH_SHORT).show(); + } + } + + /** + * @brief Removes selected color from the selected ListView item when switching from edit mode to normal mode + */ + private void restoreSelectedView() { + if (selectedView != null) { + selectedView.setBackgroundResource(0); + } + restoreColorScheme(); + } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/NavigationDrawerFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/NavigationDrawerFragment.java index 99ed2178..53aeac1d 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/NavigationDrawerFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/NavigationDrawerFragment.java @@ -1,7 +1,7 @@ package org.buildmlearn.toolkit.fragment; -import android.app.Activity; +import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.Bundle; @@ -24,7 +24,6 @@ import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.adapter.NavigationDrawerMenuAdapter; -import org.buildmlearn.toolkit.constant.Constants; import org.buildmlearn.toolkit.model.Section; /** @@ -66,9 +65,6 @@ public class NavigationDrawerFragment extends Fragment { private int selectedSectionMenu = 0; - public NavigationDrawerFragment() { - } - /** * {@inheritDoc} */ @@ -134,8 +130,8 @@ public void onItemClick(AdapterView parent, View view, int position, long id) position--; if (menus[position].getType() == Section.FRAGMENT) { - for (int i = 0; i < menus.length; i++) { - menus[i].setIsSelected(false); + for (Section menu : menus) { + menu.setIsSelected(false); } menus[position].setIsSelected(true); } @@ -153,7 +149,7 @@ public void onItemClick(AdapterView parent, View view, int position, long id) return mDrawerListView; } - public boolean isDrawerOpen() { + private boolean isDrawerOpen() { return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView); } @@ -217,7 +213,7 @@ public void onDrawerOpened(View drawerView) { mUserLearnedDrawer = true; SharedPreferences sp = PreferenceManager .getDefaultSharedPreferences(getActivity()); - sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).commit(); + sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply(); } getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu() @@ -238,7 +234,7 @@ public void run() { } }); - mDrawerLayout.setDrawerListener(mDrawerToggle); + mDrawerLayout.addDrawerListener(mDrawerToggle); } private void selectItem(int position) { @@ -247,10 +243,8 @@ private void selectItem(int position) { mDrawerListView.setItemChecked(position, true); } - if (mDrawerLayout == null || !isDrawerOpen()) { - if (mCallbacks != null) { + if ((mDrawerLayout == null || !isDrawerOpen()) && mCallbacks != null) { mCallbacks.onNavigationDrawerItemSelected(position); - } } if (mDrawerLayout != null) { mDrawerLayout.closeDrawer(mFragmentContainerView); @@ -262,10 +256,10 @@ private void selectItem(int position) { * {@inheritDoc} */ @Override - public void onAttach(Activity activity) { - super.onAttach(activity); + public void onAttach(Context context) { + super.onAttach(context); try { - mCallbacks = (NavigationDrawerCallbacks) activity; + mCallbacks = (NavigationDrawerCallbacks) context; } catch (ClassCastException e) { throw new ClassCastException("Activity must implement NavigationDrawerCallbacks."); } @@ -317,33 +311,30 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { */ @Override public boolean onOptionsItemSelected(MenuItem item) { - if (mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } + return mDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item); - return super.onOptionsItemSelected(item); } /** * Per the navigation drawer design guidelines, updates the action bar to show the global app * 'context', rather than just what's in the current screen. */ - protected void showGlobalContextActionBar() { + private void showGlobalContextActionBar() { ActionBar actionBar = getActionBar(); actionBar.setDisplayShowTitleEnabled(true); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); actionBar.setTitle(R.string.app_name); } - protected ActionBar getActionBar() { + private ActionBar getActionBar() { return ((AppCompatActivity) getActivity()).getSupportActionBar(); } /** * Callbacks interface that all activities using this fragment must implement. */ - public static interface NavigationDrawerCallbacks { + public interface NavigationDrawerCallbacks { /** * Called when an item in the navigation drawer is selected. */ diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/SettingsFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/SettingsFragment.java index cbee04d5..012d6d4e 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/SettingsFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/SettingsFragment.java @@ -1,8 +1,10 @@ package org.buildmlearn.toolkit.fragment; +import android.content.SharedPreferences; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; import android.widget.Toast; import org.buildmlearn.toolkit.R; @@ -12,10 +14,14 @@ */ public class SettingsFragment extends PreferenceFragment { + private Preference prefUsername; + private SharedPreferences preferences; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.fragment_settings); + preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); Preference button = findPreference(getString(R.string.key_delete_temporary_files)); button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @@ -25,5 +31,13 @@ public boolean onPreferenceClick(Preference preference) { return true; } }); + + prefUsername = findPreference(getString(R.string.key_user_name)); + } + + @Override + public void onResume() { + super.onResume(); + prefUsername.setSummary(preferences.getString(getString(R.string.key_user_name), "")); } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/Constants.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/Constants.java new file mode 100644 index 00000000..03169160 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/Constants.java @@ -0,0 +1,19 @@ +package org.buildmlearn.toolkit.infotemplate; + +import org.buildmlearn.toolkit.infotemplate.data.InfoContract; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class Constants { + public static final String[] INFO_COLUMNS = { + InfoContract.Info.TABLE_NAME + "." + InfoContract.Info._ID, + InfoContract.Info.TITLE, + InfoContract.Info.DESCRIPTION + }; + public static final int COL_ID = 0; + public static final int COL_TITLE = 1; + public static final int COL_DESCRIPTION = 2; + public static final String firstrun = "firstRun"; + public static String XMLFileName = "info_content.xml"; +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/DetailView.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/DetailView.java deleted file mode 100644 index dd29eebb..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/DetailView.java +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright (c) 2012, BuildmLearn Contributors listed at http://buildmlearn.org/people/ - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the BuildmLearn nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/* Copyright (c) 2012, BuildmLearn Contributors listed at http://buildmlearn.org/people/ - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the BuildmLearn nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -package org.buildmlearn.toolkit.infotemplate; - -import android.app.Fragment; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; - -/** - * @brief Simulator code for Info Template - */ -public class DetailView extends Fragment { - - public static Fragment newInstance(int position) { - DetailView fragment = new DetailView(); - Bundle bundle = new Bundle(); - bundle.putInt("position", position); - fragment.setArguments(bundle); - return fragment; - } - - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - View view = inflater.inflate(R.layout.info_template_detail, container, false); - TextView title = (TextView) view.findViewById(R.id.titleText); - TextView details = (TextView) view.findViewById(R.id.detailText); - int position = getArguments().getInt("position", 0); - InfoModel model = GlobalData.getInstance().mList.get(position); - title.setText(model.getInfo_object()); - details.setText(model.getInfo_description()); - view.findViewById(R.id.info_template_simulator_back_button).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - - getActivity().getFragmentManager().popBackStack(); - - } - }); - return view; - } -} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/GlobalData.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/GlobalData.java deleted file mode 100644 index c6875687..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/GlobalData.java +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright (c) 2012, BuildmLearn Contributors listed at http://buildmlearn.org/people/ - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the BuildmLearn nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -package org.buildmlearn.toolkit.infotemplate; - -import android.util.Log; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -/** - * @brief Simulator code for Info Template - */ -public class GlobalData { - private static GlobalData instance = null; - String mTitle, mAuthor = null; - int iSelectedIndex = -1; - ArrayList mList = null; - - protected GlobalData() { - // Exists only to defeat instantiation. - } - - public static GlobalData getInstance() { - if (instance == null) { - instance = new GlobalData(); - } - return instance; - } - - private static String getValue(String tag, Element element) { - NodeList nodeList = null; - NodeList node1 = element.getElementsByTagName(tag); - if (node1 != null && node1.getLength() != 0) - nodeList = node1.item(0).getChildNodes(); - if (nodeList == null) - return ""; - else if (nodeList.getLength() == 0) - return ""; - else { - Node node = (Node) nodeList.item(0); - - return node.getNodeValue(); - } - } - - public void readXml(String filePath) { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - - dbf.setValidating(false); - - DocumentBuilder db; - Document doc; - try { - File fXmlFile = new File(filePath); - mList = new ArrayList(); - db = dbf.newDocumentBuilder(); - doc = db.parse(fXmlFile); - doc.normalize(); - /* - * NodeList app_nodes = doc - * .getElementsByTagName("buildmlearn_application"); - */ - // NamedNodeMap node = app_nodes.item(0).getAttributes(); - mTitle = doc.getElementsByTagName("title").item(0).getChildNodes() - .item(0).getNodeValue(); - // NodeList author_nodes = doc.getElementsByTagName("author"); - // NamedNodeMap node1 = author_nodes.item(0).getAttributes(); - mAuthor = doc.getElementsByTagName("name").item(0).getChildNodes() - .item(0).getNodeValue(); - ; - // node1.getNamedItem("name").getNodeValue(); - NodeList childNodes = doc.getElementsByTagName("item"); - // Log.e("tag", "childNodes" + childNodes.getLength()); - for (int i = 0; i < childNodes.getLength(); i++) { - InfoModel app = new InfoModel(); - - Node child = childNodes.item(i); - - if (child.getNodeType() == Node.ELEMENT_NODE) { - Element element2 = (Element) child; - - app.setInfo_object(getValue("item_title", element2)); - app.setInfo_description(getValue("item_description", element2)); - - } - mList.add(app); - - } - } catch (ParserConfigurationException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } catch (FileNotFoundException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } catch (SAXException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } catch (IOException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } - - } - - -} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/InfoListAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/InfoListAdapter.java deleted file mode 100644 index 0ca14742..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/InfoListAdapter.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.buildmlearn.toolkit.infotemplate; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; - -import java.util.ArrayList; - -/** - * @brief Simulator code for Info Template - */ -public class InfoListAdapter extends BaseAdapter { - - private Context mContext; - private ArrayList mList; - - public InfoListAdapter(Context context) { - mList = new ArrayList(); - mContext = context; - } - - public void setList(ArrayList list) { - mList = list; - this.notifyDataSetChanged(); - - } - - @Override - public int getCount() { - return mList.size(); - } - - @Override - public Object getItem(int position) { - return mList.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - ViewHolder holder = null; - if (convertView == null) { - - LayoutInflater inflater = LayoutInflater.from(mContext); - convertView = inflater.inflate(R.layout.info_template_app_list_item, parent, - false); - - holder = new ViewHolder(); - holder.mTvInfoObject = (TextView) convertView - .findViewById(R.id.tv_info_object); - convertView.setTag(holder); - - } else { - holder = (ViewHolder) convertView.getTag(); - } - holder.mTvInfoObject.setTag(R.id.tv_info_object); - holder.mTvInfoObject.setText(mList.get(position).getInfo_object()); - - return convertView; - } - - public class ViewHolder { - private TextView mTvInfoObject; - } - -} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/InfoModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/InfoModel.java deleted file mode 100644 index 0aaa1802..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/InfoModel.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.buildmlearn.toolkit.infotemplate; - -/** - * @brief Simulator code for Info Template - */ -public class InfoModel { - - private String info_object, info_description; - - public String getInfo_object() { - return info_object; - } - - public void setInfo_object(String info_object) { - this.info_object = info_object; - } - - public String getInfo_description() { - return info_description; - } - - public void setInfo_description(String info_description) { - this.info_description = info_description; - } - - -} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/TFTFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/TFTFragment.java deleted file mode 100644 index d96f793c..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/TFTFragment.java +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (c) 2012, BuildmLearn Contributors listed at http://buildmlearn.org/people/ - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the BuildmLearn nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -package org.buildmlearn.toolkit.infotemplate; - -import android.app.Fragment; -import android.app.ListFragment; -import android.os.Bundle; -import android.view.View; -import android.widget.ListView; - -import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.constant.Constants; - -/** - * @brief Simulator code for Info Template - */ -public class TFTFragment extends ListFragment { - - - public static Fragment newInstance(String path) { - TFTFragment fragment = new TFTFragment(); - Bundle bundle = new Bundle(); - bundle.putString(Constants.SIMULATOR_FILE_PATH, path); - fragment.setArguments(bundle); - return fragment; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - GlobalData gd = GlobalData.getInstance(); - gd.readXml(getArguments().getString(Constants.SIMULATOR_FILE_PATH)); - InfoListAdapter adapter = new InfoListAdapter(getActivity()); - setListAdapter(adapter); - setEmptyText("No Data"); - getListView().setBackgroundColor(getResources().getColor(R.color.info_template_blue_background)); - adapter.setList(gd.mList); - - - } - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, DetailView.newInstance(position)).addToBackStack(null).commit(); - } - - -} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/adapter/InfoArrayAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/adapter/InfoArrayAdapter.java new file mode 100644 index 00000000..ac58766d --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/adapter/InfoArrayAdapter.java @@ -0,0 +1,54 @@ +package org.buildmlearn.toolkit.infotemplate.adapter; + +import android.content.Context; +import android.database.Cursor; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.infotemplate.Constants; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class InfoArrayAdapter extends CursorAdapter { + + public InfoArrayAdapter(Context context) { + super(context, null, 0); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + View view = LayoutInflater.from(context).inflate(R.layout.list_item_info, parent, false); + ViewHolder viewHolder = new ViewHolder(view); + view.setTag(viewHolder); + return view; + } + + /* + * This is where we fill-in the views with the contents of the cursor. + */ + @Override + public void bindView(View view, final Context context, Cursor cursor) { + final ViewHolder viewHolder = (ViewHolder) view.getTag(); + + String title = cursor.getString(Constants.COL_TITLE); + viewHolder.title.setText(title); + + } + + public static class ViewHolder { + + public final ImageView thumb; + public final TextView title; + + public ViewHolder(View view) { + thumb = (ImageView) view.findViewById(R.id.thumb); + title = (TextView) view.findViewById(R.id.title); + } + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/DataUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/DataUtils.java new file mode 100644 index 00000000..54334d52 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/DataUtils.java @@ -0,0 +1,44 @@ +package org.buildmlearn.toolkit.infotemplate.data; + +import org.buildmlearn.toolkit.infotemplate.Constants; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class DataUtils { + + public static String[] readTitleAuthor() { + String result[] = new String[2]; + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setValidating(false); + + DocumentBuilder db; + Document doc; + try { + File fXmlFile = new File(Constants.XMLFileName); + db = dbf.newDocumentBuilder(); + doc = db.parse(fXmlFile); + doc.normalize(); + + result[0] = doc.getElementsByTagName("title").item(0).getChildNodes() + .item(0).getNodeValue(); + + result[1] = doc.getElementsByTagName("name").item(0).getChildNodes() + .item(0).getNodeValue(); + + } catch (ParserConfigurationException | SAXException | IOException e) { + e.printStackTrace(); + } + return result; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/FetchXMLTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/FetchXMLTask.java new file mode 100644 index 00000000..2c1cb12f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/FetchXMLTask.java @@ -0,0 +1,131 @@ +package org.buildmlearn.toolkit.infotemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.os.AsyncTask; + +import org.buildmlearn.toolkit.infotemplate.Constants; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Vector; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class FetchXMLTask extends AsyncTask { + + private final Context mContext; + + public FetchXMLTask(Context context) { + mContext = context; + } + + private static String getValue(String tag, Element element) { + NodeList nodeList = null; + NodeList node1 = element.getElementsByTagName(tag); + if (node1 != null && node1.getLength() != 0) + nodeList = node1.item(0).getChildNodes(); + if (nodeList == null) + return ""; + else if (nodeList.getLength() == 0) + return ""; + else { + Node node = nodeList.item(0); + return node.getNodeValue(); + } + } + + private void saveInfoData(ArrayList Infos) { + + Vector cVVector = new Vector<>(Infos.size()); + + for (int i = 0; i < Infos.size(); i++) { + + String title; + String description; + + InfoModel InfoInfo = Infos.get(i); + + title = InfoInfo.getTitle(); + description = InfoInfo.getDescription(); + + ContentValues InfoValues = new ContentValues(); + + InfoValues.put(InfoContract.Info.TITLE, title); + InfoValues.put(InfoContract.Info.DESCRIPTION, description); + + cVVector.add(InfoValues); + } + // add to database + if (cVVector.size() > 0) { + ContentValues[] cvArray = new ContentValues[cVVector.size()]; + cVVector.toArray(cvArray); + InfoDb db = new InfoDb(mContext); + db.open(); + db.bulkInsert(cvArray); + db.close(); + } + } + + @Override + protected Void doInBackground(String... params) { + + if (params.length == 0) { + return null; + } + ArrayList mList; + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setValidating(false); + + DocumentBuilder db; + Document doc; + try { + File fXmlFile = new File(Constants.XMLFileName); + db = dbf.newDocumentBuilder(); + doc = db.parse(fXmlFile); + doc.normalize(); + mList = new ArrayList<>(); + + NodeList childNodes = doc.getElementsByTagName("item"); + + for (int i = 0; i < childNodes.getLength(); i++) { + InfoModel app = new InfoModel(); + + Node child = childNodes.item(i); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element2 = (Element) child; + + app.setTitle(getValue("item_title", element2)); + app.setDescription(getValue("item_description", element2)); + + } + mList.add(app); + } + saveInfoData(mList); + } catch (ParserConfigurationException e) { + return null; + } catch (FileNotFoundException e) { + return null; + } catch (SAXException e) { + return null; + } catch (IOException e) { + return null; + } + return null; + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoContract.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoContract.java new file mode 100644 index 00000000..0beeb43f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoContract.java @@ -0,0 +1,19 @@ +package org.buildmlearn.toolkit.infotemplate.data; + +import android.provider.BaseColumns; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ + +public class InfoContract { + + public static final class Info implements BaseColumns { + + public static final String TABLE_NAME = "mLearning"; + + public static final String TITLE = "title"; + public static final String DESCRIPTION = "description"; + + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoDBHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoDBHelper.java new file mode 100644 index 00000000..64966fcd --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoDBHelper.java @@ -0,0 +1,37 @@ +package org.buildmlearn.toolkit.infotemplate.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.buildmlearn.toolkit.infotemplate.data.InfoContract.Info; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ + +class InfoDBHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "mLearning.db"; + private static final int DATABASE_VERSION = 1; + + public InfoDBHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + final String SQL_CREATE__TABLE = "CREATE TABLE " + Info.TABLE_NAME + " (" + + Info._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Info.TITLE + " TEXT," + + Info.DESCRIPTION + " TEXT)"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE); + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Info.TABLE_NAME); + onCreate(sqLiteDatabase); + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoDb.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoDb.java new file mode 100644 index 00000000..8a028f0e --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoDb.java @@ -0,0 +1,93 @@ +package org.buildmlearn.toolkit.infotemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.support.annotation.NonNull; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class InfoDb { + + private static final String EQUAL = " == "; + private final InfoDBHelper dbHelper; + private SQLiteDatabase db; + + public InfoDb(Context context) { + dbHelper = new InfoDBHelper(context); + } + + public void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public boolean isOpen() { + return db.isOpen(); + } + + public void close() { + dbHelper.close(); + } + + public Cursor getInfosCursor() { + + return db.query( + InfoContract.Info.TABLE_NAME, + null, + null, + null, + null, + null, + null + ); + } + + public Cursor getInfoCursorById(int id) { + + String selection = InfoContract.Info._ID + EQUAL + id; + + return db.query( + InfoContract.Info.TABLE_NAME, + null, + selection, + null, + null, + null, + null + ); + } + + public long getCount() { + + return DatabaseUtils.queryNumEntries(db, + InfoContract.Info.TABLE_NAME); + } + + public void deleteAll() { + db.delete(InfoContract.Info.TABLE_NAME, null, null); + db.execSQL("delete from sqlite_sequence where name='" + InfoContract.Info.TABLE_NAME + "';"); + } + + public int bulkInsert(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(InfoContract.Info.TABLE_NAME, null, value); + if (_id != -1) { + returnCount++; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + return returnCount; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoModel.java new file mode 100644 index 00000000..201f5005 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/data/InfoModel.java @@ -0,0 +1,64 @@ +package org.buildmlearn.toolkit.infotemplate.data; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class InfoModel implements Parcelable { + public final Creator CREATOR = new Creator() { + @Override + public InfoModel createFromParcel(Parcel parcel) { + return new InfoModel(parcel); + } + + @Override + public InfoModel[] newArray(int size) { + return new InfoModel[size]; + } + }; + private String title; + private String description; + + public InfoModel() { + } + + public InfoModel(String title, String description) { + this.title = title; + this.description = description; + } + + private InfoModel(Parcel in) { + this.title = in.readString(); + this.description = in.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(title); + dest.writeString(description); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/DetailActivityFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/DetailActivityFragment.java new file mode 100644 index 00000000..f9fa9234 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/DetailActivityFragment.java @@ -0,0 +1,220 @@ +package org.buildmlearn.toolkit.infotemplate.fragment; + +import android.app.FragmentManager; +import android.content.ContentValues; +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.infotemplate.Constants; +import org.buildmlearn.toolkit.infotemplate.data.DataUtils; +import org.buildmlearn.toolkit.infotemplate.data.InfoContract; +import org.buildmlearn.toolkit.infotemplate.data.InfoDb; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class DetailActivityFragment extends Fragment implements LoaderCallbacks { + + private static final int DETAIL_LOADER = 0; + private final ContentValues infoValues; + + private View rootView; + private String info_Id; + private InfoDb db; + + public DetailActivityFragment() { + setHasOptionsMenu(true); + infoValues = new ContentValues(); + } + + public static Fragment newInstance() { + return new DetailActivityFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + Bundle arguments = getArguments(); + if (arguments != null) { + info_Id = arguments.getString(Intent.EXTRA_TEXT); + } + rootView = inflater.inflate(R.layout.fragment_detail_info, container, false); + + db = new InfoDb(getContext()); + db.open(); + Toolbar maintoolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + String result[] = DataUtils.readTitleAuthor(); + maintoolbar.setTitle(result[0]); + maintoolbar.inflateMenu(R.menu.menu_main_white); + maintoolbar.setNavigationIcon(R.drawable.ic_home_white_24dp); + + maintoolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), org.buildmlearn.toolkit.infotemplate.fragment.MainActivityFragment.newInstance()).addToBackStack(null).commit(); + } + }); + maintoolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.action_about: + AlertDialog.Builder builder = + new AlertDialog.Builder(getActivity()); + builder.setTitle(String.format("%1$s", getString(R.string.about_us))); + builder.setMessage(getResources().getText(R.string.about_text_video)); + builder.setPositiveButton("OK", null); + AlertDialog welcomeAlert = builder.create(); + welcomeAlert.show(); + assert welcomeAlert.findViewById(android.R.id.message) != null; + assert welcomeAlert.findViewById(android.R.id.message) != null; + ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + break; + default: //do nothing + break; + } + return true; + } + }); + + return rootView; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + getLoaderManager().initLoader(DETAIL_LOADER, null, this); + super.onActivityCreated(savedInstanceState); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + if (null != info_Id) { + switch (id) { + case DETAIL_LOADER: + + return new CursorLoader(getActivity(), null, Constants.INFO_COLUMNS, null, null, null) { + @Override + public Cursor loadInBackground() { + return db.getInfoCursorById(Integer.parseInt(info_Id)); + } + }; + default: //do nothing + break; + } + } + return null; + } + + @Override + public void onLoadFinished(Loader loader, final Cursor data) { + if (!data.moveToFirst()) { + return; + } + switch (loader.getId()) { + case DETAIL_LOADER: + String title = data.getString(Constants.COL_TITLE); + + ((TextView) rootView.findViewById(R.id.title)) + .setText(title); + + String description = data.getString(Constants.COL_DESCRIPTION); + + ((TextView) rootView.findViewById(R.id.description)) + .setText(description); + + final long numColumns = db.getCount(); + + if (Integer.parseInt(info_Id) == numColumns) { + + rootView.findViewById(R.id.next).setVisibility(View.INVISIBLE); + rootView.findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().finish(); + } + }); + + } else { + + rootView.findViewById(R.id.exit).setVisibility(View.INVISIBLE); + rootView.findViewById(R.id.next).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + long nextInfoId = Integer.parseInt(info_Id) + 1; + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(nextInfoId)); + + Fragment frag = DetailActivityFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + + } + }); + } + + if (Integer.parseInt(info_Id) == 1) { + + rootView.findViewById(R.id.previous).setVisibility(View.INVISIBLE); + + } else { + + rootView.findViewById(R.id.previous).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + int prevInfoId = Integer.parseInt(info_Id) - 1; + + if (prevInfoId >= 1) { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(prevInfoId)); + + Fragment frag = DetailActivityFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + + } + } + }); + } + + if (infoValues.size() == 0) { + infoValues.put(InfoContract.Info._ID, data.getString(Constants.COL_ID)); + infoValues.put(InfoContract.Info.TITLE, data.getString(Constants.COL_TITLE)); + infoValues.put(InfoContract.Info.DESCRIPTION, data.getString(Constants.COL_DESCRIPTION)); + } + break; + default: + throw new UnsupportedOperationException("Unknown Loader"); + } + } + + @Override + public void onLoaderReset(Loader loader) { + //This constructor is intentionally empty + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + db.close(); + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/MainActivityFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/MainActivityFragment.java new file mode 100644 index 00000000..711ddb62 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/MainActivityFragment.java @@ -0,0 +1,181 @@ +package org.buildmlearn.toolkit.infotemplate.fragment; + +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.infotemplate.Constants; +import org.buildmlearn.toolkit.infotemplate.adapter.InfoArrayAdapter; +import org.buildmlearn.toolkit.infotemplate.data.DataUtils; +import org.buildmlearn.toolkit.infotemplate.data.InfoContract; +import org.buildmlearn.toolkit.infotemplate.data.InfoDb; +import org.buildmlearn.toolkit.infotemplate.data.InfoModel; + +import java.util.ArrayList; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class MainActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks { + + private static final String SELECTED_KEY = "selected_position"; + private static final int INFO_LOADER = 0; + + private InfoArrayAdapter infoListAdapter; + private int mPosition = ListView.INVALID_POSITION; + private ListView listView; + private ArrayList infoList; + private View rootView; + private InfoDb db; + + public static Fragment newInstance() { + return new MainActivityFragment(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putParcelableArrayList("infoList", infoList); + if (mPosition != ListView.INVALID_POSITION) { + outState.putInt(SELECTED_KEY, mPosition); + } + super.onSaveInstanceState(outState); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState == null || !savedInstanceState.containsKey("infoList")) { + infoList = new ArrayList<>(); + } else { + infoList = savedInstanceState.getParcelableArrayList("infoList"); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + infoListAdapter = + new InfoArrayAdapter( + getActivity()); + + rootView = inflater.inflate(R.layout.fragment_main_info, container, false); + + Toolbar maintoolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + final String result[] = DataUtils.readTitleAuthor(); + maintoolbar.setTitle(result[0]); + maintoolbar.inflateMenu(R.menu.menu_main_white); + maintoolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.action_about: + AlertDialog.Builder builder = + new AlertDialog.Builder(getActivity()); + builder.setTitle(String.format("%1$s", getString(R.string.about_us))); + builder.setMessage(getResources().getText(R.string.about_text_info)); + builder.setPositiveButton("OK", null); + AlertDialog welcomeAlert = builder.create(); + welcomeAlert.show(); + assert ((TextView) welcomeAlert.findViewById(android.R.id.message)) != null; + ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + break; + default: //do nothing + break; + } + return true; + } + }); + + listView = (ListView) rootView.findViewById(R.id.list_view_info); + listView.setAdapter(infoListAdapter); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(position + 1)); + + Fragment frag = org.buildmlearn.toolkit.infotemplate.fragment.DetailActivityFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + mPosition = position; + } + }); + + db = new InfoDb(getContext()); + db.open(); + + if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY)) { + mPosition = savedInstanceState.getInt(SELECTED_KEY); + } + return rootView; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + getLoaderManager().initLoader(INFO_LOADER, null, this); + super.onActivityCreated(savedInstanceState); + } + + @Override + public Loader onCreateLoader(int i, Bundle bundle) { + + String sortOrder = InfoContract.Info._ID + " ASC"; + + return new CursorLoader(getActivity(), null, Constants.INFO_COLUMNS, null, null, sortOrder) { + @Override + public Cursor loadInBackground() { + return db.getInfosCursor(); + } + }; + } + + @Override + public void onLoadFinished(Loader cursorLoader, Cursor cursor) { + infoListAdapter.swapCursor(cursor); + if (mPosition != ListView.INVALID_POSITION) { + listView.smoothScrollToPosition(mPosition); + } + try { + TextView info = (TextView) rootView.findViewById(R.id.empty); + if (infoListAdapter.getCount() == 0) { + info.setText(R.string.list_empty_info); + info.setVisibility(View.VISIBLE); + } else { + info.setVisibility(View.GONE); + } + } catch (Exception ignored) { + } + } + + @Override + public void onLoaderReset(Loader cursorLoader) { + infoListAdapter.swapCursor(null); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + ViewGroup mContainer = (ViewGroup) getActivity().findViewById(R.id.container); + mContainer.removeAllViews(); + db.close(); + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/SplashFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/SplashFragment.java new file mode 100644 index 00000000..144e3acc --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/infotemplate/fragment/SplashFragment.java @@ -0,0 +1,64 @@ +package org.buildmlearn.toolkit.infotemplate.fragment; + +import android.app.Activity; +import android.app.FragmentManager; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.infotemplate.Constants; +import org.buildmlearn.toolkit.infotemplate.data.DataUtils; +import org.buildmlearn.toolkit.infotemplate.data.FetchXMLTask; +import org.buildmlearn.toolkit.infotemplate.data.InfoDb; +import org.buildmlearn.toolkit.views.TextViewPlus; + +/** + * Created by Anupam (opticod) on 20/6/16. + */ +public class SplashFragment extends Fragment { + + public static Fragment newInstance(String path) { + SplashFragment fragment = new SplashFragment(); + Constants.XMLFileName = path; + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_splash, container, false); + + final Activity mActivity = getActivity(); + final String result[] = DataUtils.readTitleAuthor(); + TextView title = (TextView) rootView.findViewById(R.id.title); + TextView author_name = (TextView) rootView.findViewById(R.id.author_name); + + title.setText(result[0]); + author_name.setText(result[1]); + ((TextViewPlus) rootView.findViewById(R.id.intro_text)).setText(getResources().getString(R.string.main_title_info)); + + rootView.findViewById(R.id.enter).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), MainActivityFragment.newInstance()).addToBackStack(null).commit(); + } + }); + + InfoDb db = new InfoDb(mActivity); + db.open(); + db.deleteAll(); + + long numColumns = db.getCount(); + db.close(); + if (numColumns == 0) { + FetchXMLTask xmlTask = new FetchXMLTask(getActivity()); + xmlTask.execute(Constants.XMLFileName); + } + return rootView; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/DataManager.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/DataManager.java index 7e223cc3..21f326d9 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/DataManager.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/DataManager.java @@ -36,7 +36,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -53,7 +52,6 @@ public class DataManager { private static DataManager instance = null; private String mTitle = null; private String mAuthor = null; - private BufferedReader br; private ArrayList mList = null; private int countIndex = 0; private int countCorrect = 0; @@ -76,7 +74,7 @@ private static String getValue(String tag, Element element) { else if (nodeList.getLength() == 0) return ""; else { - Node node = (Node) nodeList.item(0); + Node node = nodeList.item(0); return node.getNodeValue(); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/ResultActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/ResultActivity.java index 57cdafef..1208731d 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/ResultActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/ResultActivity.java @@ -28,10 +28,10 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.buildmlearn.toolkit.learnspelling; -import android.app.Fragment; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -47,21 +47,19 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * @brief Simulator code for Learn Spelling Template */ public class ResultActivity extends Fragment { - private TextView mTv_Correct, mTv_Wrong, mTv_Unanswered; private DataManager mDataManager; private TextToSpeech textToSpeech; private int unanswered, wrong, correct; - private View view; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - view = inflater.inflate(R.layout.spelling_fragment_finish, container, false); + View view = inflater.inflate(R.layout.spelling_fragment_finish, container, false); mDataManager = DataManager.getInstance(); - mTv_Correct = (TextView) view.findViewById(R.id.tv_correct); - mTv_Wrong = (TextView) view.findViewById(R.id.tv_wrong); - mTv_Unanswered = (TextView) view.findViewById(R.id.tv_unanswered); + TextView mTv_Correct = (TextView) view.findViewById(R.id.tv_correct); + TextView mTv_Wrong = (TextView) view.findViewById(R.id.tv_wrong); + TextView mTv_Unanswered = (TextView) view.findViewById(R.id.tv_unanswered); correct = mDataManager.getCorrect(); wrong = mDataManager.getWrong(); unanswered = mDataManager.getList().size() - correct - wrong; @@ -100,7 +98,7 @@ public void onClick(View v) { @Override public void onClick(View v) { mDataManager.reset(); - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, SpellingMainFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), StartFragment.TAG).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, SpellingMainFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), StartFragment.TAG).addToBackStack(null).commit(); //t } }); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingActivity.java index 5e051fe5..4bf4f997 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingActivity.java @@ -30,11 +30,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE import android.app.AlertDialog; import android.app.AlertDialog.Builder; -import android.app.Fragment; import android.graphics.Color; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -65,13 +65,12 @@ public class SpellingActivity extends Fragment implements private Button mBtn_Spell, mBtn_Skip; private EditText mEt_Spelling; private SeekBar mSb_SpeechRate; - private View view; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - view = inflater.inflate(R.layout.spelling_fragment_spelling, container, false); + View view = inflater.inflate(R.layout.spelling_fragment_spelling, container, false); mBtn_Spell = (Button) view.findViewById(R.id.btn_ready); @@ -100,7 +99,7 @@ public void onClick(View v) { mBtn_Skip.setTextColor(Color.WHITE); mBtn_Spell.setTextColor(Color.WHITE); } else { - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new ResultActivity()).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new ResultActivity()).addToBackStack(null).commit(); } } }); @@ -181,9 +180,9 @@ public void onInit(int status) { } } - public void submit() { + private void submit() { String input = mEt_Spelling.getText().toString().trim(); - if (input == null || input.length() == 0) { + if (input.length() == 0) { Toast.makeText(getActivity(), "Please enter the spelling", Toast.LENGTH_SHORT).show(); @@ -198,15 +197,14 @@ public void submit() { mManager.incrementWrong(); } - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, WordInfoActivity.newInstance(isCorrect, count, input)).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, WordInfoActivity.newInstance(isCorrect, count, input)).addToBackStack(null).commit(); } } private float getProgressValue(int percent) { float temp = ((float) percent / 100); - float per = temp * 2; - return per; + return temp * 2; } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingMainFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingMainFragment.java index 74ff2d4e..b807666d 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingMainFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingMainFragment.java @@ -28,9 +28,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.buildmlearn.toolkit.learnspelling; -import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -46,10 +46,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ public class SpellingMainFragment extends Fragment { - private Button mBtn_Start; - private DataManager mManager; - private TextView mTv_Title, mTv_Author; - public static Fragment newInstance(String path) { SpellingMainFragment fragment = new SpellingMainFragment(); Bundle bundle = new Bundle(); @@ -64,19 +60,19 @@ public static Fragment newInstance(String path) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.spelling_fragment_main, container, false); - mBtn_Start = (Button) view.findViewById(R.id.btn_start); - mTv_Title = (TextView) view.findViewById(R.id.tv_apptitle); - mTv_Author = (TextView) view.findViewById(R.id.tv_author); + Button mBtn_Start = (Button) view.findViewById(R.id.btn_start); + TextView mTv_Title = (TextView) view.findViewById(R.id.tv_apptitle); + TextView mTv_Author = (TextView) view.findViewById(R.id.tv_author); mBtn_Start.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new SpellingActivity()).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new SpellingActivity()).addToBackStack(null).commit(); } }); - mManager = DataManager.getInstance(); + DataManager mManager = DataManager.getInstance(); mManager.readXml(getArguments().getString(Constants.SIMULATOR_FILE_PATH)); mTv_Title.setText(mManager.getTitle()); mTv_Author.setText(mManager.getAuthor()); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordInfoActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordInfoActivity.java index 9403a534..5049dad9 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordInfoActivity.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordInfoActivity.java @@ -28,11 +28,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.buildmlearn.toolkit.learnspelling; -import android.app.Fragment; import android.graphics.Color; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -51,14 +51,9 @@ public class WordInfoActivity extends Fragment { private boolean isCorrect; private int position; - private TextView mTv_Result, mTv_enteredWord, mTv_word, mTv_description, - mTv_Word_num; private DataManager mManager; private ArrayList mList; - private Button mBtn_Next; private TextToSpeech textToSpeech; - private String enteredText; - private View view; public static Fragment newInstance(boolean isCorrect, int count, String word) { Fragment fragment = new WordInfoActivity(); @@ -76,20 +71,20 @@ public static Fragment newInstance(boolean isCorrect, int count, String word) { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - view = inflater.inflate(R.layout.spelling_fragment_word_info, container, false); + View view = inflater.inflate(R.layout.spelling_fragment_word_info, container, false); mManager = DataManager.getInstance(); mList = mManager.getList(); isCorrect = getArguments().getBoolean("result", false); position = getArguments().getInt("index", 0); - enteredText = getArguments().getString("word"); - mTv_Result = (TextView) view.findViewById(R.id.tv_result); - mTv_Word_num = (TextView) view.findViewById(R.id.tv_word_num); - mTv_word = (TextView) view.findViewById(R.id.tv_word); - mTv_enteredWord = (TextView) view.findViewById(R.id.tv_input_word); - - mTv_description = (TextView) view.findViewById(R.id.tv_description); - mBtn_Next = (Button) view.findViewById(R.id.btn_next); + String enteredText = getArguments().getString("word"); + TextView mTv_Result = (TextView) view.findViewById(R.id.tv_result); + TextView mTv_Word_num = (TextView) view.findViewById(R.id.tv_word_num); + TextView mTv_word = (TextView) view.findViewById(R.id.tv_word); + TextView mTv_enteredWord = (TextView) view.findViewById(R.id.tv_input_word); + + TextView mTv_description = (TextView) view.findViewById(R.id.tv_description); + Button mBtn_Next = (Button) view.findViewById(R.id.btn_next); if (position == mList.size() - 1) { mBtn_Next.setText("Finish"); } @@ -127,9 +122,9 @@ public void onInit(int arg0) { public void onClick(View v) { if (position < mList.size() - 1) { mManager.increaseCount(); - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new SpellingActivity()).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new SpellingActivity()).addToBackStack(null).commit(); } else { - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new ResultActivity()).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new ResultActivity()).addToBackStack(null).commit(); } } }); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordModel.java index cd330376..6d677370 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordModel.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordModel.java @@ -31,7 +31,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE /** * @brief Simulator code for Learn Spelling Template */ -public class WordModel { +class WordModel { private String mWord; private String mDescription; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/KeyStoreDetails.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/KeyStoreDetails.java index a6deba6a..bd983e95 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/KeyStoreDetails.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/KeyStoreDetails.java @@ -7,10 +7,10 @@ */ public class KeyStoreDetails { - private String assetsPath; - private String password; - private String alias; - private String aliasPassword; + private final String assetsPath; + private final String password; + private final String alias; + private final String aliasPassword; public KeyStoreDetails(String assetsPath, String password, String alias, String aliasPassword) { this.assetsPath = assetsPath; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/SavedProject.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/SavedProject.java index b2de3263..8c2ee211 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/SavedProject.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/SavedProject.java @@ -10,13 +10,12 @@ */ public class SavedProject { + private final String fullPath; private File file; - private String name; private String date; private String type; private String author; - private String fullPath; public SavedProject(File file, String fileName, long date, String type, String fullPath) { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/Template.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/Template.java index 64e40d6f..85a762ca 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/Template.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/Template.java @@ -4,10 +4,12 @@ import android.support.annotation.StringRes; import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.templates.ComprehensionTemplate; import org.buildmlearn.toolkit.templates.FlashTemplate; import org.buildmlearn.toolkit.templates.InfoTemplate; import org.buildmlearn.toolkit.templates.LearnSpellingTemplate; import org.buildmlearn.toolkit.templates.QuizTemplate; +import org.buildmlearn.toolkit.templates.VideoCollectionTemplate; /** * @brief Enum for the templates that are included into toolkit application. @@ -16,23 +18,29 @@ */ public enum Template { - BASIC_M_LEARNING(R.string.basic_m_learning_title, R.string.basic_m_learning_description, R.drawable.basic_m_learning, R.string.info_template, InfoTemplate.class), + BASIC_M_LEARNING(R.string.basic_m_learning_title, R.string.basic_m_learning_description, R.drawable.info_template, R.string.info_template, InfoTemplate.class), LEARN_SPELLING(R.string.learn_spellings_title, R.string.learn_spellings_description, R.drawable.basic_m_learning, R.string.spelling_type, LearnSpellingTemplate.class), QUIZ(R.string.quiz_title, R.string.quiz_description, R.drawable.basic_m_learning, R.string.quiz_type, QuizTemplate.class), - FLASH_CARD(R.string.flash_card_title, R.string.flash_card_description, R.drawable.basic_m_learning, R.string.flash_card_template, FlashTemplate.class); + FLASH_CARD(R.string.flash_card_title, R.string.flash_card_description, R.drawable.basic_m_learning, R.string.flash_card_template, FlashTemplate.class), + VIDEO_COLLECTION(R.string.video_collection_title, R.string.video_collection_description, R.drawable.video_collection, R.string.video_collection_template, VideoCollectionTemplate.class), + COMPREHENSION(R.string.comprehension_title, R.string.comprehension_description, R.drawable.comprehension, R.string.comprehension_template, ComprehensionTemplate.class); @StringRes + final int type; private @DrawableRes + final int image; private @StringRes + final int title; private @StringRes + final int description; - private Class templateClass; + private final Class templateClass; Template(@StringRes int title, @StringRes int description, @DrawableRes int image, @StringRes int type, Class templateClass) { this.image = image; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/TemplateInterface.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/TemplateInterface.java index ccc7e422..3dc9fcf3 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/TemplateInterface.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/TemplateInterface.java @@ -1,7 +1,6 @@ package org.buildmlearn.toolkit.model; import android.app.Activity; -import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.widget.BaseAdapter; @@ -28,12 +27,27 @@ public interface TemplateInterface extends Serializable { */ BaseAdapter newTemplateEditorAdapter(Context context); + /** + * @param context Application context + * @return BaseAdapter inherited Object + * @brief Called from Template Editor when template editor is started for creating a new meta details of template project. + */ + BaseAdapter newMetaEditorAdapter(Context context); + /** * @return BaseAdapter inherited Object * @brief This function is used to get the adapter (containing template data) for a existing/current template project. */ BaseAdapter currentTemplateEditorAdapter(); + /** + * @return BaseAdapter inherited Object + * @brief This function is used to get the meta adapter (containing template meta details) for a existing/current template project. + */ + BaseAdapter currentMetaEditorAdapter(); + + BaseAdapter loadProjectMetaEditor(Context context, Document doc); + BaseAdapter loadProjectTemplateEditor(Context context, ArrayList data); /** @@ -54,6 +68,13 @@ public interface TemplateInterface extends Serializable { */ void addItem(Activity activity); + /** + * + * @param activity Current Activity + * @brief Add MetaData to template data + */ + void addMetaData(Activity activity); + /** * @param activity Current activity * @param position Position of the item in the template data list @@ -62,10 +83,11 @@ public interface TemplateInterface extends Serializable { void editItem(Activity activity, int position); /** + * @param activity Current Activity * @param position Position of the item to be removed * @brief Remove an item form template data list */ - void deleteItem(int position); + void deleteItem(Activity activity, int position); ArrayList getItems(Document doc); @@ -78,7 +100,7 @@ public interface TemplateInterface extends Serializable { * Returns a fragment required for the Simulator Activity. * **Dev Note: File Path should be used to populate data from actual .buildmlearn file in the Simulator. */ - Fragment getSimulatorFragment(String filePathWithName); + android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName); /** * @return Asset file name @@ -108,4 +130,8 @@ public interface TemplateInterface extends Serializable { */ void onActivityResult(Context context, int requestCode, int resultCode, Intent intent); + /** + * @brief Toggles the visibility of empty text if Array has zero elements + */ + void setEmptyView(Activity activity); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/Tutorial.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/Tutorial.java index ad41b80c..04c0ab95 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/Tutorial.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/Tutorial.java @@ -22,14 +22,17 @@ public enum Tutorial { private @DrawableRes + final int image; private @StringRes + final int title; private @StringRes + final int description; - private boolean isLastScreen; + private final boolean isLastScreen; Tutorial(int image, int title, int description) { this.image = image; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/GlobalData.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/GlobalData.java index 15622478..2b8551ce 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/GlobalData.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/GlobalData.java @@ -42,7 +42,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; @@ -57,20 +56,17 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ public class GlobalData { private static GlobalData instance = null; + final List iQuizList = new ArrayList<>(); String iQuizTitle = null; String iQuizAuthor = null; ArrayList model = null; - - BufferedReader br; - - List iQuizList = new ArrayList(); int correct = 0; int wrong = 0; int total = 0; - int iSelectedIndex = -1; + private BufferedReader br; - protected GlobalData() { + private GlobalData() { // Exists only to defeat instantiation. } @@ -139,10 +135,10 @@ public void readXmlContent(Context myContext, String fileName) { QuestionModel app = null; while (eventType != XmlPullParser.END_DOCUMENT) { - String name = null; + String name; switch (eventType) { case XmlPullParser.START_DOCUMENT: - model = new ArrayList(); + model = new ArrayList<>(); break; case XmlPullParser.START_TAG: name = parser.getName(); @@ -153,7 +149,7 @@ public void readXmlContent(Context myContext, String fileName) { iQuizAuthor = parser.nextText(); } else if (name.equalsIgnoreCase("item")) { app = new QuestionModel(); - mOptions = new ArrayList(); + mOptions = new ArrayList<>(); } else if (app != null) { if (name.equalsIgnoreCase("question")) { app.setQuestion(parser.nextText()); @@ -175,10 +171,8 @@ public void readXmlContent(Context myContext, String fileName) { eventType = parser.next(); } - } catch (XmlPullParserException e1) { + } catch (XmlPullParserException | IOException e1) { e1.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); } // return model; // BuildmLearnModel.getInstance(myContext).setAllAppsList(model); @@ -190,12 +184,12 @@ public void readXml(String filePath) { dbf.setValidating(false); - ArrayList mOptions = null; + ArrayList mOptions; DocumentBuilder db; Document doc; try { File fXmlFile = new File(filePath); - model = new ArrayList(); + model = new ArrayList<>(); db = dbf.newDocumentBuilder(); doc = db.parse(fXmlFile); doc.normalize(); @@ -214,7 +208,7 @@ public void readXml(String filePath) { Element element2 = (Element) child; app.setQuestion(getValue("question", element2)); - mOptions = new ArrayList(); + mOptions = new ArrayList<>(); NodeList optionNodes = element2 .getElementsByTagName("option"); for (int j = 0; j < optionNodes.getLength(); j++) { @@ -227,18 +221,12 @@ public void readXml(String filePath) { } total = model.size(); - } catch (ParserConfigurationException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } catch (FileNotFoundException e) { + } catch (ParserConfigurationException | IOException e) { Log.e("tag", e.getLocalizedMessage()); e.printStackTrace(); } catch (SAXException e) { Log.e("tag", e.getLocalizedMessage()); e.printStackTrace(); - } catch (IOException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionFragment.java index 3c685f21..5d20d2df 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionFragment.java @@ -28,10 +28,10 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.buildmlearn.toolkit.quiztemplate; -import android.app.Fragment; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; @@ -54,37 +54,32 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE public class QuestionFragment extends Fragment { public final static String TAG = "QUESTION_FRAGMENT"; - + private final List iRadButtonList = new ArrayList<>(); private GlobalData gd; private TextView iQuestion_no_Label; private TextView iQuestionLabel; - private RadioButton iRad1, iRad2, iRad3, iRad0; - private Button iSubmitButton, iNextButton; - private List iRadButtonList = new ArrayList(); + private Button iSubmitButton; private int iQuestionIndex = 0; private int iCurrentCorrectAnswer; - private RadioGroup iRadioGroup; - private FragmentActivity faActivity; - private View view; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - faActivity = (FragmentActivity) super.getActivity(); - view = inflater.inflate(R.layout.quiz_template_fragment_questions_view, container, false); + FragmentActivity faActivity = super.getActivity(); + View view = inflater.inflate(R.layout.quiz_template_fragment_questions_view, container, false); gd = GlobalData.getInstance(); iQuestion_no_Label = (TextView) view.findViewById(R.id.question_no); iQuestionLabel = (TextView) view.findViewById(R.id.question_label); - iRad0 = (RadioButton) view.findViewById(R.id.radio0); - iRad1 = (RadioButton) view.findViewById(R.id.radio1); - iRad2 = (RadioButton) view.findViewById(R.id.radio2); - iRad3 = (RadioButton) view.findViewById(R.id.radio3); + RadioButton iRad0 = (RadioButton) view.findViewById(R.id.radio0); + RadioButton iRad1 = (RadioButton) view.findViewById(R.id.radio1); + RadioButton iRad2 = (RadioButton) view.findViewById(R.id.radio2); + RadioButton iRad3 = (RadioButton) view.findViewById(R.id.radio3); - iRadioGroup = (RadioGroup) view.findViewById(R.id.radioGroup1); + RadioGroup iRadioGroup = (RadioGroup) view.findViewById(R.id.radioGroup1); iRadButtonList.add(iRad0); iRadButtonList.add(iRad1); @@ -100,8 +95,7 @@ public void onClick(View arg0) { if (selectedAnswer == -1) { Toast.makeText(getActivity(), "Please select an answer!", Toast.LENGTH_LONG).show(); - } else if (selectedAnswer != -1 - && selectedAnswer == iCurrentCorrectAnswer) { + } else if (selectedAnswer == iCurrentCorrectAnswer) { iRadButtonList.get(iCurrentCorrectAnswer) .setBackgroundColor(Color.GREEN); Toast.makeText(getActivity(), @@ -126,7 +120,7 @@ public void onClick(View arg0) { } }); - iNextButton = (Button) view.findViewById(R.id.next_button); + Button iNextButton = (Button) view.findViewById(R.id.next_button); iNextButton.setOnClickListener(new OnClickListener() { @Override @@ -148,7 +142,7 @@ public void onClick(View arg0) { } else { // if the quiz is over reInitialize(); - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new ScoreFragment(), ScoreFragment.TAG).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new ScoreFragment(), ScoreFragment.TAG).addToBackStack(null).commit(); } } }); @@ -160,11 +154,7 @@ public void onClick(View arg0) { } - public void radioClick(View v) { - - } - - public void populateQuestion(int index) { + private void populateQuestion(int index) { for (int i = 0; i < iRadButtonList.size(); i++) { iRadButtonList.get(i).setBackgroundColor(Color.TRANSPARENT); iRadButtonList.get(i).setChecked(false); @@ -184,7 +174,7 @@ public void populateQuestion(int index) { } - public int getSelectedAnswer() { + private int getSelectedAnswer() { int selected = -1; for (int i = 0; i < iRadButtonList.size(); i++) { if (iRadButtonList.get(i).isChecked()) { @@ -194,7 +184,7 @@ public int getSelectedAnswer() { return selected; } - public void reInitialize() { + private void reInitialize() { iQuestionIndex = 0; gd.iQuizList.clear(); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionModel.java index 99375beb..60f24c1b 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionModel.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionModel.java @@ -5,7 +5,7 @@ /** * @brief Simulator code for Quiz Template */ -public class QuestionModel { +class QuestionModel { private String question, answer; private ArrayList options; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/ScoreFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/ScoreFragment.java index 296e6546..8f67a8a7 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/ScoreFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/ScoreFragment.java @@ -29,9 +29,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.buildmlearn.toolkit.quiztemplate; -import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; @@ -50,23 +50,18 @@ public class ScoreFragment extends Fragment { public final static String TAG = "SCORE_FRAGMENT"; - private GlobalData gd; - private TextView mTv_correct, mTv_wrong, mTv_unanswered; - private FragmentActivity faActivity; - private View view; - @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - faActivity = (FragmentActivity) super.getActivity(); - view = inflater.inflate(R.layout.quiz_template_fragment_score_view, container, false); + FragmentActivity faActivity = super.getActivity(); + View view = inflater.inflate(R.layout.quiz_template_fragment_score_view, container, false); - gd = GlobalData.getInstance(); + GlobalData gd = GlobalData.getInstance(); - mTv_correct = (TextView) view.findViewById(R.id.tv_correct); - mTv_wrong = (TextView) view.findViewById(R.id.tv_wrong); - mTv_unanswered = (TextView) view.findViewById(R.id.tv_unanswered); + TextView mTv_correct = (TextView) view.findViewById(R.id.tv_correct); + TextView mTv_wrong = (TextView) view.findViewById(R.id.tv_wrong); + TextView mTv_unanswered = (TextView) view.findViewById(R.id.tv_unanswered); mTv_correct.setText("Total Correct: " + gd.correct); mTv_wrong.setText("Total Wrong: " + gd.wrong); int unanswered = gd.total - gd.correct - gd.wrong; @@ -77,7 +72,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa @Override public void onClick(View arg0) { - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, TFTQuizFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), TFTQuizFragment.TAG).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, TFTQuizFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), TFTQuizFragment.TAG).addToBackStack(null).commit(); } }); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/TFTQuizFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/TFTQuizFragment.java index 5390c64c..fb39acbb 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/TFTQuizFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/TFTQuizFragment.java @@ -28,9 +28,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE package org.buildmlearn.toolkit.quiztemplate; -import android.app.Fragment; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -50,7 +50,6 @@ public class TFTQuizFragment extends Fragment { private GlobalData gd; - private View view; public static Fragment newInstance(String path) { TFTQuizFragment fragment = new TFTQuizFragment(); @@ -64,7 +63,7 @@ public static Fragment newInstance(String path) { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - view = inflater.inflate(R.layout.quiz_template_fragment_start_view, container, false); + View view = inflater.inflate(R.layout.quiz_template_fragment_start_view, container, false); gd = GlobalData.getInstance(); reInitialize(); @@ -82,7 +81,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa @Override public void onClick(View arg0) { - getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new QuestionFragment(), QuestionFragment.TAG).addToBackStack(null).commit(); + getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new QuestionFragment(), QuestionFragment.TAG).addToBackStack(null).commit(); } }); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/simulator/Simulator.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/simulator/Simulator.java index 4691de3e..7316105e 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/simulator/Simulator.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/simulator/Simulator.java @@ -1,6 +1,8 @@ package org.buildmlearn.toolkit.simulator; import android.os.Bundle; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; @@ -23,7 +25,6 @@ public class Simulator extends AppCompatActivity { private static final String TAG = "SIMULATOR"; private int templateId; private TemplateInterface selectedTemplate; - private Template template; /** * {@inheritDoc} @@ -34,6 +35,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_simulator); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); ActionBar actionBar = getSupportActionBar(); + assert actionBar != null; actionBar.setDisplayHomeAsUpEnabled(true); templateId = getIntent().getIntExtra(Constants.TEMPLATE_ID, -1); if (templateId == -1) { @@ -46,7 +48,8 @@ protected void onCreate(Bundle savedInstanceState) { } else { restoreTemplateEditor(savedInstanceState); } - getFragmentManager().beginTransaction().replace(R.id.container, selectedTemplate.getSimulatorFragment(getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), selectedTemplate.getTitle()).addToBackStack(null).commit(); + + getSupportFragmentManager().beginTransaction().replace(R.id.container, selectedTemplate.getSimulatorFragment(getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), selectedTemplate.getTitle()).addToBackStack(null).commit(); } /** @@ -67,8 +70,6 @@ public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - onBackPressed(); return super.onOptionsItemSelected(item); @@ -77,9 +78,9 @@ public boolean onOptionsItemSelected(MenuItem item) { /** * @brief Fetches the instance from the Template Enum for given template object */ - protected void setUpTemplateEditor() { + private void setUpTemplateEditor() { Template[] templates = Template.values(); - template = templates[templateId]; + Template template = templates[templateId]; Class templateClass = template.getTemplateClass(); try { Object templateObject = templateClass.newInstance(); @@ -95,7 +96,7 @@ protected void setUpTemplateEditor() { /** * @brief Restores simulator state on configuration change */ - protected void restoreTemplateEditor(Bundle savedInstanceState) { + private void restoreTemplateEditor(Bundle savedInstanceState) { Log.d(TAG, "Activity Restored"); selectedTemplate = (TemplateInterface) savedInstanceState.getSerializable(Constants.TEMPLATE_OBJECT); if (selectedTemplate == null) { @@ -113,4 +114,23 @@ protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); } + @Override + public void onBackPressed() { + + int count = getSupportFragmentManager().getBackStackEntryCount(); + if (count == 1) { + finish(); + } + DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); + if (drawer != null) { + if (drawer.isDrawerOpen(GravityCompat.START)) { + drawer.closeDrawer(GravityCompat.START); + } else { + super.onBackPressed(); + } + } else { + super.onBackPressed(); + } + } + } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionAdapter.java new file mode 100644 index 00000000..75612e9f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionAdapter.java @@ -0,0 +1,279 @@ +package org.buildmlearn.toolkit.templates; + +import android.content.Context; +import android.support.v4.content.ContextCompat; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.Toast; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.activity.TemplateEditor; +import org.buildmlearn.toolkit.views.TextViewPlus; + +import java.util.ArrayList; + +/** + * Created by Anupam (opticod) on 26/5/16. + */ +class ComprehensionAdapter extends BaseAdapter { + + + private final Context context; + private final ArrayList comprehensionData; + private int expandedPostion = -1; + + public ComprehensionAdapter(Context context, ArrayList comprehensionData) { + this.context = context; + this.comprehensionData = comprehensionData; + } + + @Override + public int getCount() { + return comprehensionData.size(); + } + + @Override + public ComprehensionModel getItem(int position) { + return comprehensionData.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + LayoutInflater mInflater; + mInflater = LayoutInflater.from(context); + Holder holder; + if (convertView == null) { + convertView = mInflater.inflate(R.layout.quiz_item, parent, false); + holder = new Holder(); + + holder.question = (TextViewPlus) convertView.findViewById(R.id.question); + holder.options = new ArrayList<>(); + holder.options.add((TextViewPlus) convertView.findViewById(R.id.answer1)); + holder.options.add((TextViewPlus) convertView.findViewById(R.id.answer2)); + holder.options.add((TextViewPlus) convertView.findViewById(R.id.answer3)); + holder.options.add((TextViewPlus) convertView.findViewById(R.id.answer4)); + holder.questionIcon = (ImageView) convertView.findViewById(R.id.question_icon); + holder.quizOptionsBox = (LinearLayout) convertView.findViewById(R.id.quiz_options_box); + holder.delete = (Button) convertView.findViewById(R.id.quiz_item_delete); + holder.edit = (Button) convertView.findViewById(R.id.quiz_item_edit); + + } else { + holder = (Holder) convertView.getTag(); + } + + ComprehensionModel data = getItem(position); + holder.question.setText(data.getQuestion()); + if (data.isSelected()) { + holder.questionIcon.setImageResource(R.drawable.collapse); + holder.quizOptionsBox.setVisibility(View.VISIBLE); + } else { + holder.questionIcon.setImageResource(R.drawable.expand); + holder.quizOptionsBox.setVisibility(View.GONE); + } + + for (int i = 0; i < holder.options.size(); i++) { + if (i < data.getOptions().size()) { + int ascii = 65 + i; + holder.options.get(i).setText(Character.toString((char) ascii) + ") " + data.getOptions().get(i)); + holder.options.get(i).setTextColor(ContextCompat.getColor(context, R.color.black_secondary_text)); + holder.options.get(i).setVisibility(View.VISIBLE); + } else { + holder.options.get(i).setVisibility(View.GONE); + } + } + + holder.options.get(data.getCorrectAnswer()).setCustomFont(context, "roboto_medium.ttf"); + holder.options.get(data.getCorrectAnswer()).setTextColor(ContextCompat.getColor(context, R.color.quiz_correct_answer)); + + holder.questionIcon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (expandedPostion >= 0 && expandedPostion != position && getItem(expandedPostion) != null) { + getItem(expandedPostion).setIsSelected(false); + } + if (getItem(position).isSelected()) { + getItem(position).setIsSelected(false); + expandedPostion = -1; + } else { + getItem(position).setIsSelected(true); + expandedPostion = position; + } + notifyDataSetChanged(); + } + }); + + holder.edit.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + editItem(position, context); + } + }); + holder.delete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + final MaterialDialog dialog = new MaterialDialog.Builder(context) + .title(R.string.dialog_delete_title) + .content(R.string.dialog_delete_msg) + .positiveText(R.string.dialog_yes) + .negativeText(R.string.dialog_no) + .build(); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + comprehensionData.remove(position); + notifyDataSetChanged(); + dialog.dismiss(); + + ((TemplateEditor) context).restoreSelectedView(); + expandedPostion = -1; + } + }); + + dialog.show(); + } + }); + convertView.setTag(holder); + return convertView; + } + + private void editItem(final int position, final Context context) { + ComprehensionModel data = getItem(position); + + boolean wrapInScrollView = true; + final MaterialDialog dialog = new MaterialDialog.Builder(context) + .title(R.string.quiz_edit) + .customView(R.layout.quiz_dialog_add_question, wrapInScrollView) + .positiveText(R.string.quiz_add) + .negativeText(R.string.quiz_cancel) + .build(); + + final EditText question = (EditText) dialog.findViewById(R.id.quiz_question); + final ArrayList buttons = new ArrayList<>(); + final ArrayList options = new ArrayList<>(); + options.add((EditText) dialog.findViewById(R.id.quiz_option_1)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_2)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_3)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_4)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_1)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_2)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_3)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_4)); + + for (int i = 0; i < data.getOptions().size(); i++) { + options.get(i).setText(data.getOptions().get(i)); + } + + question.setText(data.getQuestion()); + buttons.get(data.getCorrectAnswer()).setChecked(true); + + for (final RadioButton button : buttons) { + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkButton(buttons, options, button.getId(), context); + } + }); + } + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + boolean isValidated = true; + int checkedAns = getCheckedAnswer(buttons); + if (checkedAns < 0) { + Toast.makeText(context, "Choose a correct option", Toast.LENGTH_SHORT).show(); + isValidated = false; + } + if (question.getText().toString().equals("")) { + + question.setError("Question is required"); + isValidated = false; + } + + int optionCount = 0; + for (EditText option : options) { + if (!option.getText().toString().equals("")) { + optionCount++; + } + } + if (optionCount < 2) { + Toast.makeText(context, "Minimum two multiple answers are required.", Toast.LENGTH_SHORT).show(); + isValidated = false; + } + + if (isValidated) { + dialog.dismiss(); + ArrayList answerOptions = new ArrayList<>(); + int correctAnswer = 0; + for (int i = 0; i < buttons.size(); i++) { + if (buttons.get(i).isChecked() && !options.get(i).getText().toString().equals("")) { + correctAnswer = answerOptions.size(); + answerOptions.add(options.get(i).getText().toString()); + } else if (!options.get(i).getText().toString().equals("")) { + answerOptions.add(options.get(i).getText().toString()); + } + } + String questionText = question.getText().toString(); + comprehensionData.set(position, new ComprehensionModel(questionText, answerOptions, correctAnswer)); + notifyDataSetChanged(); + } + + } + }); + dialog.show(); + + } + + private void checkButton(ArrayList buttons, ArrayList options, int id, Context context) { + for (RadioButton button : buttons) { + if (button.getId() == id) { + int index = buttons.indexOf(button); + if (options.get(index).getText().toString().equals("")) { + Toast.makeText(context, "Enter a valid option before marking it as answer", Toast.LENGTH_LONG).show(); + button.setChecked(false); + return; + } else { + button.setChecked(true); + } + } else { + button.setChecked(false); + } + } + } + + private int getCheckedAnswer(ArrayList buttons) { + for (int i = 0; i < buttons.size(); i++) { + if (buttons.get(i).isChecked()) { + return i; + } + } + return -1; + } + + public class Holder { + TextViewPlus question; + ImageView questionIcon; + ArrayList options; + LinearLayout quizOptionsBox; + Button delete; + Button edit; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionMetaAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionMetaAdapter.java new file mode 100644 index 00000000..c87cc6f6 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionMetaAdapter.java @@ -0,0 +1,76 @@ +package org.buildmlearn.toolkit.templates; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.views.TextViewPlus; + +import java.util.ArrayList; + +/** + * @brief Adapter for displaying Meta Details of Comprehension Template Editor data. + *

+ * Created by Anupam (opticod) on 26/5/16. + */ +class ComprehensionMetaAdapter extends BaseAdapter { + + private final Context mContext; + private final ArrayList data; + + public ComprehensionMetaAdapter(Context mContext, ArrayList data) { + this.mContext = mContext; + this.data = data; + } + + @Override + public int getCount() { + return data.size(); + } + + @Override + public ComprehensionMetaModel getItem(int position) { + return data.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + + ComprehensionMetaHolder holder; + + if (convertView == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + convertView = inflater.inflate(R.layout.comprehension_meta_item, parent, false); + holder = new ComprehensionMetaHolder(); + } else { + holder = (ComprehensionMetaHolder) convertView.getTag(); + } + + holder.title = (TextViewPlus) convertView.findViewById(R.id.title); + holder.passage = (TextViewPlus) convertView.findViewById(R.id.passage); + holder.timer = (TextViewPlus) convertView.findViewById(R.id.timer); + + ComprehensionMetaModel meta = getItem(position); + + holder.title.setText(meta.getTitle()); + holder.passage.setText(meta.getPassage()); + holder.timer.setText(meta.getTime() + " sec"); + convertView.setTag(holder); + + return convertView; + } + + public class ComprehensionMetaHolder { + public TextViewPlus title; + public TextViewPlus timer; + public TextViewPlus passage; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionMetaModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionMetaModel.java new file mode 100644 index 00000000..86173cdf --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionMetaModel.java @@ -0,0 +1,65 @@ +package org.buildmlearn.toolkit.templates; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.Serializable; + +/** + * @brief Model class for Comprehension Meta Template Editor data + * Created by Anupam (opticod) on 26/5/16. + */ +public class ComprehensionMetaModel implements Serializable { + + public static final String TITLE_TAG = "meta_title"; + public static final String PASSAGE_TAG = "meta_passage"; + public static final String TIMER_TAG = "meta_timer"; + private static final String ROOT_TAG = "meta_details"; + private String title; + private String passage; + private long time; + + public ComprehensionMetaModel(String title, String passage, long time) { + this.title = title; + this.passage = passage; + this.time = time; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPassage() { + return this.passage; + } + + public void setPassage(String passage) { + this.passage = passage; + } + + public long getTime() { + return this.time; + } + + public void setTime(long time) { + this.time = time; + } + + public Element getXml(Document doc) { + Element rootElement = doc.createElement(ROOT_TAG); + Element titleElement = doc.createElement(TITLE_TAG); + titleElement.appendChild(doc.createTextNode(title)); + rootElement.appendChild(titleElement); + Element passageElement = doc.createElement(PASSAGE_TAG); + passageElement.appendChild(doc.createTextNode(passage)); + rootElement.appendChild(passageElement); + Element timeElement = doc.createElement(TIMER_TAG); + timeElement.appendChild(doc.createTextNode(String.valueOf(time))); + rootElement.appendChild(timeElement); + return rootElement; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionModel.java new file mode 100644 index 00000000..f6673ec3 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionModel.java @@ -0,0 +1,80 @@ +package org.buildmlearn.toolkit.templates; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.Serializable; +import java.util.ArrayList; + +/** + * @brief Model class for Comprehension Template Editor data + *

+ * Created by Anupam (opticod) on 26/5/16. + */ +public class ComprehensionModel implements Serializable { + + private String question; + private ArrayList options; + private int correctAnswer; + private boolean isSelected; + + public ComprehensionModel(String question, ArrayList options, int correctAnswer) { + this.question = question; + this.options = options; + this.correctAnswer = correctAnswer; + this.isSelected = false; + } + + public ComprehensionModel() { + + } + + public String getQuestion() { + return question; + } + + public void setQuestion(String question) { + this.question = question; + } + + public ArrayList getOptions() { + return options; + } + + public void setOptions(ArrayList options) { + this.options = options; + } + + public int getCorrectAnswer() { + return correctAnswer; + } + + public void setCorrectAnswer(int correctAnswer) { + this.correctAnswer = correctAnswer; + } + + public Element getXml(Document doc) { + Element rootElement = doc.createElement("item"); + Element questionElement = doc.createElement("question"); + questionElement.appendChild(doc.createTextNode(question)); + rootElement.appendChild(questionElement); + for (String option : options) { + Element optionElement = doc.createElement("option"); + optionElement.appendChild(doc.createTextNode(option)); + rootElement.appendChild(optionElement); + } + + Element answerElement = doc.createElement("answer"); + answerElement.appendChild(doc.createTextNode(String.valueOf(correctAnswer))); + rootElement.appendChild(answerElement); + return rootElement; + } + + public boolean isSelected() { + return isSelected; + } + + public void setIsSelected(boolean isSelected) { + this.isSelected = isSelected; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionTemplate.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionTemplate.java new file mode 100644 index 00000000..61b1249f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/ComprehensionTemplate.java @@ -0,0 +1,534 @@ +package org.buildmlearn.toolkit.templates; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.view.View; +import android.widget.BaseAdapter; +import android.widget.EditText; +import android.widget.RadioButton; +import android.widget.TextView; +import android.widget.Toast; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.comprehensiontemplate.fragment.SplashFragment; +import org.buildmlearn.toolkit.model.TemplateInterface; +import org.buildmlearn.toolkit.utilities.FileDialog; +import org.buildmlearn.toolkit.views.TextViewPlus; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; + +/** + * Created by Anupam (opticod) on 26/5/16. + */ +public class ComprehensionTemplate implements TemplateInterface { + + private final String TEMPLATE_NAME = "Comprehension Template"; + private final ArrayList metaData; + transient private ComprehensionAdapter adapter; + transient private ComprehensionMetaAdapter metaAdapter; + private ArrayList comprehensionData; + transient private Context mContext; + + public ComprehensionTemplate() { + comprehensionData = new ArrayList<>(); + metaData = new ArrayList<>(); + } + + private static boolean validated(Context context, EditText title, EditText passage, EditText timer) { + if (title == null || passage == null || timer == null) { + return false; + } + + String titleText = title.getText().toString(); + String passageText = passage.getText().toString(); + String timerText = timer.getText().toString(); + + if (timerText.length() > 9) { + Toast.makeText(context, R.string.comprehension_template_timer_correct_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (titleText.equals("")) { + Toast.makeText(context, R.string.comprehension_template_title_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (passageText.equals("")) { + Toast.makeText(context, R.string.comprehension_template_passage_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (timerText.equals("")) { + Toast.makeText(context, R.string.comprehension_template_timer_hint, Toast.LENGTH_SHORT).show(); + return false; + } + + return true; + } + + @Override + public BaseAdapter newTemplateEditorAdapter(Context context) { + mContext = context; + adapter = new ComprehensionAdapter(context, comprehensionData); + return adapter; + } + + public BaseAdapter newMetaEditorAdapter(Context context) { + mContext = context; + metaAdapter = new ComprehensionMetaAdapter(context, metaData); + setEmptyView((Activity) context); + return metaAdapter; + } + + @Override + public BaseAdapter currentTemplateEditorAdapter() { + return adapter; + } + + public BaseAdapter currentMetaEditorAdapter() { + return metaAdapter; + } + + @Override + public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList data) { + comprehensionData = new ArrayList<>(); + for (Element item : data) { + String question = item.getElementsByTagName("question").item(0).getTextContent(); + NodeList options = item.getElementsByTagName("option"); + ArrayList answers = new ArrayList<>(); + for (int i = 0; i < options.getLength(); i++) { + answers.add(options.item(i).getTextContent()); + } + int answer = Integer.parseInt(item.getElementsByTagName("answer").item(0).getTextContent()); + comprehensionData.add(new ComprehensionModel(question, answers, answer)); + + } + adapter = new ComprehensionAdapter(context, comprehensionData); + return adapter; + } + + public BaseAdapter loadProjectMetaEditor(Context context, Document doc) { + + String title = doc.getElementsByTagName(ComprehensionMetaModel.TITLE_TAG).item(0).getTextContent(); + String passage = doc.getElementsByTagName(ComprehensionMetaModel.PASSAGE_TAG).item(0).getTextContent(); + long timer = Long.parseLong(doc.getElementsByTagName(ComprehensionMetaModel.TIMER_TAG).item(0).getTextContent()); + metaData.add(new ComprehensionMetaModel(title, passage, timer)); + metaAdapter = new ComprehensionMetaAdapter(context, metaData); + setEmptyView((Activity) context); + + return metaAdapter; + + } + + @Override + public String onAttach() { + return TEMPLATE_NAME; + } + + @Override + public String getTitle() { + return TEMPLATE_NAME; + } + + private void checkButton(ArrayList buttons, ArrayList options, int id, Context context) { + for (RadioButton button : buttons) { + if (button.getId() == id) { + int index = buttons.indexOf(button); + if (options.get(index).getText().toString().equals("")) { + Toast.makeText(context, "Enter a valid option before marking it as answer", Toast.LENGTH_LONG).show(); + button.setChecked(false); + return; + } else { + button.setChecked(true); + } + } else { + button.setChecked(false); + } + } + } + + private int getCheckedAnswer(ArrayList buttons) { + for (int i = 0; i < buttons.size(); i++) { + if (buttons.get(i).isChecked()) { + return i; + } + } + return -1; + } + + @Override + public void addItem(final Activity activity) { + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.quiz_new_question_title) + .customView(R.layout.quiz_dialog_add_question, true) + .positiveText(R.string.quiz_add) + .negativeText(R.string.quiz_cancel) + .build(); + + final EditText question = (EditText) dialog.findViewById(R.id.quiz_question); + final ArrayList buttons = new ArrayList<>(); + final ArrayList options = new ArrayList<>(); + options.add((EditText) dialog.findViewById(R.id.quiz_option_1)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_2)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_3)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_4)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_1)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_2)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_3)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_4)); + + for (final RadioButton button : buttons) { + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkButton(buttons, options, button.getId(), activity); + } + }); + } + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + boolean isValidated = true; + int checkedAns = getCheckedAnswer(buttons); + if (checkedAns < 0) { + Toast.makeText(activity, "Choose a correct option", Toast.LENGTH_SHORT).show(); + isValidated = false; + } + if (question.getText().toString().equals("")) { + + question.setError("Question is required"); + isValidated = false; + } + + int optionCount = 0; + for (EditText option : options) { + if (!option.getText().toString().equals("")) { + optionCount++; + } + } + if (optionCount < 2) { + Toast.makeText(activity, "Minimum two multiple answers are required.", Toast.LENGTH_SHORT).show(); + isValidated = false; + } + + if (isValidated) { + dialog.dismiss(); + ArrayList answerOptions = new ArrayList<>(); + int correctAnswer = 0; + for (int i = 0; i < buttons.size(); i++) { + if (buttons.get(i).isChecked() && !options.get(i).getText().toString().equals("")) { + correctAnswer = answerOptions.size(); + answerOptions.add(options.get(i).getText().toString()); + } else if (!options.get(i).getText().toString().equals("")) { + answerOptions.add(options.get(i).getText().toString()); + } + } + String questionText = question.getText().toString(); + comprehensionData.add(new ComprehensionModel(questionText, answerOptions, correctAnswer)); + setEmptyView(activity); + adapter.notifyDataSetChanged(); + } + + } + }); + dialog.show(); + + } + + @Override + public void addMetaData(final Activity activity) { + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.comprehension_add_meta_title) + .customView(R.layout.comprehension_meta_dialog_add_edit_data, true) + .positiveText(R.string.info_template_add) + .negativeText(R.string.info_template_cancel) + .build(); + + final EditText title = (EditText) dialog.findViewById(R.id.meta_title); + final EditText passage = (EditText) dialog.findViewById(R.id.meta_passage); + final EditText timer = (EditText) dialog.findViewById(R.id.meta_timer); + + dialog.findViewById(R.id.upload).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + FileDialog fileDialog = new FileDialog(activity); + fileDialog.setFileEndsWith(".txt"); + fileDialog.addFileListener(new FileDialog.FileSelectListener() { + public void fileSelected(File file) { + ((TextView) dialog.findViewById(R.id.file_name)).setText(file.toString()); + ((TextView) dialog.findViewById(R.id.meta_passage)).setText(readFile(file)); + } + }); + fileDialog.showDialog(); + } + }); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (validated(activity, title, passage, timer)) { + + String titleText = title.getText().toString(); + String passageText = passage.getText().toString(); + long timerLong = Long.parseLong(timer.getText().toString()); + ComprehensionMetaModel temp = new ComprehensionMetaModel(titleText, passageText, timerLong); + metaData.add(temp); + setEmptyView(activity); + metaAdapter.notifyDataSetChanged(); + dialog.dismiss(); + } + } + }); + + dialog.show(); + } + + @Override + public void editItem(final Activity activity, final int position) { + if (position == -2) { + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.comprehension_edit_meta_title) + .customView(R.layout.comprehension_meta_dialog_add_edit_data, true) + .positiveText(R.string.info_template_ok) + .negativeText(R.string.info_template_cancel) + .build(); + + final ComprehensionMetaModel data = metaData.get(0); + + final EditText title = (EditText) dialog.findViewById(R.id.meta_title); + final EditText passage = (EditText) dialog.findViewById(R.id.meta_passage); + final EditText timer = (EditText) dialog.findViewById(R.id.meta_timer); + title.setText(data.getTitle()); + passage.setText(data.getPassage()); + timer.setText(String.valueOf(data.getTime())); + + dialog.findViewById(R.id.upload).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + FileDialog fileDialog = new FileDialog(activity); + fileDialog.setFileEndsWith(".txt"); + fileDialog.addFileListener(new FileDialog.FileSelectListener() { + public void fileSelected(File file) { + ((TextView) dialog.findViewById(R.id.file_name)).setText(file.toString()); + ((TextView) dialog.findViewById(R.id.meta_passage)).setText(readFile(file)); + } + }); + fileDialog.showDialog(); + } + }); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (validated(activity, title, passage, timer)) { + + String titleText = title.getText().toString(); + String passageText = passage.getText().toString(); + long timerLong = Long.parseLong(timer.getText().toString()); + + data.setTitle(titleText); + data.setPassage(passageText); + data.setTime(timerLong); + metaAdapter.notifyDataSetChanged(); + dialog.dismiss(); + } + } + }); + + dialog.show(); + + } else { + + ComprehensionModel data = comprehensionData.get(position); + + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.quiz_edit) + .customView(R.layout.quiz_dialog_add_question, true) + .positiveText(R.string.quiz_ok) + .negativeText(R.string.quiz_cancel) + .build(); + + final EditText question = (EditText) dialog.findViewById(R.id.quiz_question); + final ArrayList buttons = new ArrayList<>(); + final ArrayList options = new ArrayList<>(); + options.add((EditText) dialog.findViewById(R.id.quiz_option_1)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_2)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_3)); + options.add((EditText) dialog.findViewById(R.id.quiz_option_4)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_1)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_2)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_3)); + buttons.add((RadioButton) dialog.findViewById(R.id.quiz_radio_4)); + + for (int i = 0; i < data.getOptions().size(); i++) { + options.get(i).setText(data.getOptions().get(i)); + } + + question.setText(data.getQuestion()); + buttons.get(data.getCorrectAnswer()).setChecked(true); + + for (final RadioButton button : buttons) { + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + checkButton(buttons, options, button.getId(), activity); + } + }); + } + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + boolean isValidated = true; + int checkedAns = getCheckedAnswer(buttons); + if (checkedAns < 0) { + Toast.makeText(activity, "Choose a correct option", Toast.LENGTH_SHORT).show(); + isValidated = false; + } + if (question.getText().toString().equals("")) { + + question.setError("Question is required"); + isValidated = false; + } + + int optionCount = 0; + for (EditText option : options) { + if (!option.getText().toString().equals("")) { + optionCount++; + } + } + if (optionCount < 2) { + Toast.makeText(activity, "Minimum two multiple answers are required.", Toast.LENGTH_SHORT).show(); + isValidated = false; + } + + if (isValidated) { + dialog.dismiss(); + ArrayList answerOptions = new ArrayList<>(); + int correctAnswer = 0; + for (int i = 0; i < buttons.size(); i++) { + if (buttons.get(i).isChecked() && !options.get(i).getText().toString().equals("")) { + correctAnswer = answerOptions.size(); + answerOptions.add(options.get(i).getText().toString()); + } else if (!options.get(i).getText().toString().equals("")) { + answerOptions.add(options.get(i).getText().toString()); + } + } + String questionText = question.getText().toString(); + comprehensionData.set(position, new ComprehensionModel(questionText, answerOptions, correctAnswer)); + adapter.notifyDataSetChanged(); + } + + } + }); + dialog.show(); + } + } + + @Override + public void deleteItem(Activity activity, int position) { + if (position == -2) { + metaData.remove(0); + setEmptyView(activity); + metaAdapter.notifyDataSetChanged(); + } else { + comprehensionData.remove(position); + setEmptyView(activity); + adapter.notifyDataSetChanged(); + } + } + + @Override + public ArrayList getItems(Document doc) { + ArrayList itemElements = new ArrayList<>(); + + for (ComprehensionMetaModel data : metaData) { + itemElements.add(data.getXml(doc)); + } + + for (ComprehensionModel data : comprehensionData) { + + itemElements.add(data.getXml(doc)); + } + + return itemElements; + } + + @Override + public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { + return SplashFragment.newInstance(filePathWithName); + } + + @Override + public String getAssetsFileName() { + return "comprehension_content.xml"; + } + + @Override + public String getAssetsFilePath() { + return "assets/"; + } + + @Override + public String getApkFilePath() { + return "ComprehensionApp.apk"; + } + + @Override + public void onActivityResult(Context context, int requestCode, int resultCode, Intent intent) { + + } + + /** + * @brief Toggles the visibility of empty text if Array has zero elements + */ + @Override + public void setEmptyView(Activity activity) { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && metaData.size() > 0) { + activity.findViewById(R.id.shadow_meta).setVisibility(View.VISIBLE); + } + if (comprehensionData.size() < 1 && metaData.size() < 1) { + activity.findViewById(R.id.shadow_meta).setVisibility(View.GONE); + ((TextViewPlus) activity.findViewById(R.id.empty_view_text)).setText(R.string.meta_add_help); + activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); + } else if (comprehensionData.size() < 1) { + ((TextViewPlus) activity.findViewById(R.id.empty_view_text)).setText(R.string.add_item_help); + activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); + } else if (metaData.size() < 1) { + activity.findViewById(R.id.shadow_meta).setVisibility(View.GONE); + ((TextViewPlus) activity.findViewById(R.id.empty_view_text)).setText(R.string.meta_add_help); + activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); + } else { + activity.findViewById(R.id.empty).setVisibility(View.GONE); + } + } + + private String readFile(File file) { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + reader.close(); + return sb.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + return ""; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardAdapter.java index a5b48534..3533d5f2 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardAdapter.java @@ -23,10 +23,10 @@ * * Created by abhishek on 12/07/15 at 11:56 PM. */ -public class FlashCardAdapter extends BaseAdapter { +class FlashCardAdapter extends BaseAdapter { - private Context mContext; - private ArrayList mData; + private final Context mContext; + private final ArrayList mData; public FlashCardAdapter(Context context, ArrayList data) { mContext = context; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardModel.java index ac5db0b4..84441282 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardModel.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardModel.java @@ -17,10 +17,10 @@ */ public class FlashCardModel implements Serializable { - private String mQuestion; - private String mAnswer; - private String mHint; - private String mImage; + private final String mQuestion; + private final String mAnswer; + private final String mHint; + private final String mImage; public FlashCardModel(String question, String answer, String hint, Bitmap image) { mQuestion = question; @@ -41,9 +41,8 @@ private String convertBitmapToBase64(Bitmap image) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); byte[] byteArray = byteArrayOutputStream.toByteArray(); - String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT); - return encoded; + return Base64.encodeToString(byteArray, Base64.DEFAULT); } @@ -65,8 +64,7 @@ public String getImage() { public Bitmap getImageBitmap() { byte[] decodedString = Base64.decode(mImage, Base64.DEFAULT); - Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); - return decodedByte; + return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); } public Element getXml(Document doc) { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashTemplate.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashTemplate.java index 570850c4..d870792b 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashTemplate.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashTemplate.java @@ -1,7 +1,6 @@ package org.buildmlearn.toolkit.templates; import android.app.Activity; -import android.app.Fragment; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -41,7 +40,7 @@ public class FlashTemplate implements TemplateInterface { private static final int REQUEST_TAKE_PHOTO = 6677; private static final String TAG = "FLASH TEMPLATE"; - ArrayList mData; + private ArrayList mData; transient private Uri mImageUri; transient private ImageView mBannerImage; private boolean mIsPhotoAttached; @@ -55,14 +54,30 @@ public FlashTemplate() { public BaseAdapter newTemplateEditorAdapter(Context context) { mAdapter = new FlashCardAdapter(context, mData); + setEmptyView((Activity) context); return mAdapter; } + @Override + public BaseAdapter newMetaEditorAdapter(Context context) { + return null; + } + @Override public BaseAdapter currentTemplateEditorAdapter() { return mAdapter; } + @Override + public BaseAdapter currentMetaEditorAdapter() { + return null; + } + + @Override + public BaseAdapter loadProjectMetaEditor(Context context, Document doc) { + return null; + } + @Override public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList data) { @@ -76,6 +91,7 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList } mAdapter = new FlashCardAdapter(context, mData); + setEmptyView((Activity) context); return mAdapter; } @@ -141,6 +157,7 @@ public void onClick(View v) { String answerText = answer.getText().toString(); String hintText = answerHint.getText().toString(); mData.add(new FlashCardModel(questionText, answerText, hintText, bitmap)); + setEmptyView(activity); mAdapter.notifyDataSetChanged(); } @@ -150,6 +167,11 @@ public void onClick(View v) { dialog.show(); } + @Override + public void addMetaData(Activity activity) { + + } + @Override public void editItem(final Activity activity, int position) { @@ -240,8 +262,9 @@ private boolean validateData(EditText question, EditText answer, EditText answer } @Override - public void deleteItem(int position) { + public void deleteItem(Activity activity, int position) { mData.remove(position); + setEmptyView(activity); mAdapter.notifyDataSetChanged(); } @@ -260,7 +283,7 @@ public ArrayList getItems(Document doc) { } @Override - public Fragment getSimulatorFragment(String filePathWithName) { + public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { return StartFragment.newInstance(filePathWithName); } @@ -378,5 +401,16 @@ private File createTemporaryFile(Context context, String part, String ext) throw return File.createTempFile(part, ext, tempDir); } + /** + * @brief Toggles the visibility of empty text if Array has zero elements + */ + @Override + public void setEmptyView(Activity activity) { + if (mData.size() < 1) { + activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); + } else { + activity.findViewById(R.id.empty).setVisibility(View.GONE); + } + } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/InfoAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/InfoAdapter.java index c7ef0e20..a602f43b 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/InfoAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/InfoAdapter.java @@ -22,10 +22,10 @@ *

* Created by abhishek on 17/06/15 at 9:48 PM. */ -public class InfoAdapter extends BaseAdapter { +class InfoAdapter extends BaseAdapter { - private Context mContext; - private ArrayList data; + private final Context mContext; + private final ArrayList data; public InfoAdapter(Context mContext, ArrayList data) { this.mContext = mContext; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/InfoTemplate.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/InfoTemplate.java index 09252ed0..5c5600ca 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/InfoTemplate.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/InfoTemplate.java @@ -1,7 +1,6 @@ package org.buildmlearn.toolkit.templates; import android.app.Activity; -import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.view.View; @@ -13,7 +12,7 @@ import com.afollestad.materialdialogs.MaterialDialog; import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.infotemplate.TFTFragment; +import org.buildmlearn.toolkit.infotemplate.fragment.SplashFragment; import org.buildmlearn.toolkit.model.TemplateInterface; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -56,14 +55,30 @@ public static boolean validated(Context context, EditText word, EditText meaning @Override public BaseAdapter newTemplateEditorAdapter(Context context) { adapter = new InfoAdapter(context, infoData); + setEmptyView((Activity) context); return adapter; } + @Override + public BaseAdapter newMetaEditorAdapter(Context context) { + return null; + } + @Override public BaseAdapter currentTemplateEditorAdapter() { return adapter; } + @Override + public BaseAdapter currentMetaEditorAdapter() { + return null; + } + + @Override + public BaseAdapter loadProjectMetaEditor(Context context, Document doc) { + return null; + } + @Override public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList data) { infoData = new ArrayList<>(); @@ -73,6 +88,7 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList infoData.add(new InfoModel(infoObject, infoDescription)); } adapter = new InfoAdapter(context, infoData); + setEmptyView((Activity) context); return adapter; } @@ -110,6 +126,7 @@ public void onClick(View v) { InfoModel temp = new InfoModel(wordText, meaningText); infoData.add(temp); adapter.notifyDataSetChanged(); + setEmptyView(activity); dialog.dismiss(); } @@ -120,6 +137,11 @@ public void onClick(View v) { } + @Override + public void addMetaData(Activity activity) { + + } + @Override public void editItem(final Activity activity, int position) { final MaterialDialog dialog = new MaterialDialog.Builder(activity) @@ -159,10 +181,11 @@ public void onClick(View v) { } @Override - public void deleteItem(int position) { + public void deleteItem(Activity activity, int position) { infoData.remove(position); + setEmptyView(activity); adapter.notifyDataSetChanged(); } @@ -181,8 +204,8 @@ public ArrayList getItems(Document doc) { } @Override - public Fragment getSimulatorFragment(String filePathWithName) { - return TFTFragment.newInstance(filePathWithName); + public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { + return SplashFragment.newInstance(filePathWithName); } @Override @@ -205,4 +228,15 @@ public void onActivityResult(Context context, int requestCode, int resultCode, I } + /** + * @brief Toggles the visibility of empty text if Array has zero elements + */ + @Override + public void setEmptyView(Activity activity) { + if (infoData.size() < 1) { + activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); + } else { + activity.findViewById(R.id.empty).setVisibility(View.GONE); + } + } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/LearnSpellingAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/LearnSpellingAdapter.java index 9e184f60..c1589b32 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/LearnSpellingAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/LearnSpellingAdapter.java @@ -22,10 +22,10 @@ * * Created by abhishek on 17/06/15 at 9:48 PM. */ -public class LearnSpellingAdapter extends BaseAdapter { +class LearnSpellingAdapter extends BaseAdapter { - private Context mContext; - private ArrayList data; + private final Context mContext; + private final ArrayList data; public LearnSpellingAdapter(Context mContext, ArrayList data) { this.mContext = mContext; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/LearnSpellingTemplate.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/LearnSpellingTemplate.java index c5548e9d..100f06d2 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/LearnSpellingTemplate.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/LearnSpellingTemplate.java @@ -1,7 +1,6 @@ package org.buildmlearn.toolkit.templates; import android.app.Activity; -import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.view.View; @@ -34,7 +33,7 @@ public LearnSpellingTemplate() { mLearnSpellingData = new ArrayList<>(); } - public static boolean validated(Context context, EditText word, EditText meaning) { + private static boolean validated(Context context, EditText word, EditText meaning) { if (word == null || meaning == null) { return false; } @@ -56,14 +55,30 @@ public static boolean validated(Context context, EditText word, EditText meaning @Override public BaseAdapter newTemplateEditorAdapter(Context context) { adapter = new LearnSpellingAdapter(context, mLearnSpellingData); + setEmptyView((Activity) context); return adapter; } + @Override + public BaseAdapter newMetaEditorAdapter(Context context) { + return null; + } + @Override public BaseAdapter currentTemplateEditorAdapter() { return adapter; } + @Override + public BaseAdapter currentMetaEditorAdapter() { + return null; + } + + @Override + public BaseAdapter loadProjectMetaEditor(Context context, Document doc) { + return null; + } + @Override public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList data) { mLearnSpellingData = new ArrayList<>(); @@ -73,6 +88,7 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList mLearnSpellingData.add(new LearnSpellingModel(infoObject, infoDescription)); } adapter = new LearnSpellingAdapter(context, mLearnSpellingData); + setEmptyView((Activity) context); return adapter; } @@ -110,6 +126,7 @@ public void onClick(View v) { LearnSpellingModel temp = new LearnSpellingModel(wordText, meaningText); mLearnSpellingData.add(temp); adapter.notifyDataSetChanged(); + setEmptyView(activity); dialog.dismiss(); } @@ -120,6 +137,11 @@ public void onClick(View v) { } + @Override + public void addMetaData(Activity activity) { + + } + @Override public void editItem(final Activity activity, int position) { final MaterialDialog dialog = new MaterialDialog.Builder(activity) @@ -159,10 +181,11 @@ public void onClick(View v) { } @Override - public void deleteItem(int position) { + public void deleteItem(Activity activity, int position) { mLearnSpellingData.remove(position); + setEmptyView(activity); adapter.notifyDataSetChanged(); } @@ -181,7 +204,7 @@ public ArrayList getItems(Document doc) { } @Override - public Fragment getSimulatorFragment(String filePathWithName) { + public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { return SpellingMainFragment.newInstance(filePathWithName); } @@ -205,4 +228,15 @@ public void onActivityResult(Context context, int requestCode, int resultCode, I } + /** + * @brief Toggles the visibility of empty text if Array has zero elements + */ + @Override + public void setEmptyView(Activity activity) { + if (mLearnSpellingData.size() < 1) { + activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); + } else { + activity.findViewById(R.id.empty).setVisibility(View.GONE); + } + } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizAdapter.java index b5fedaec..461819da 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizAdapter.java @@ -1,6 +1,7 @@ package org.buildmlearn.toolkit.templates; import android.content.Context; +import android.support.v4.content.ContextCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -26,11 +27,11 @@ *

* Created by abhishek on 28/5/15. */ -public class QuizAdapter extends BaseAdapter { +class QuizAdapter extends BaseAdapter { - private Context context; - private ArrayList quizData; + private final Context context; + private final ArrayList quizData; private int expandedPostion = -1; public QuizAdapter(Context context, ArrayList quizData) { @@ -91,6 +92,7 @@ public View getView(final int position, View convertView, ViewGroup parent) { if (i < data.getOptions().size()) { int ascii = 65 + i; holder.options.get(i).setText(Character.toString((char) ascii) + ") " + data.getOptions().get(i)); + holder.options.get(i).setTextColor(ContextCompat.getColor(context, R.color.black_secondary_text)); holder.options.get(i).setVisibility(View.VISIBLE); } else { holder.options.get(i).setVisibility(View.GONE); @@ -98,7 +100,7 @@ public View getView(final int position, View convertView, ViewGroup parent) { } holder.options.get(data.getCorrectAnswer()).setCustomFont(context, "roboto_medium.ttf"); - holder.options.get(data.getCorrectAnswer()).setTextColor(context.getResources().getColor(R.color.quiz_correct_answer)); + holder.options.get(data.getCorrectAnswer()).setTextColor(ContextCompat.getColor(context, R.color.quiz_correct_answer)); holder.questionIcon.setOnClickListener(new View.OnClickListener() { @Override @@ -221,7 +223,7 @@ public void onClick(View v) { if (isValidated) { dialog.dismiss(); - ArrayList answerOptions = new ArrayList(); + ArrayList answerOptions = new ArrayList<>(); int correctAnswer = 0; for (int i = 0; i < buttons.size(); i++) { if (buttons.get(i).isChecked() && !options.get(i).getText().toString().equals("")) { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizTemplate.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizTemplate.java index 17f0a30d..ed4d6126 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizTemplate.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizTemplate.java @@ -1,7 +1,6 @@ package org.buildmlearn.toolkit.templates; import android.app.Activity; -import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.view.View; @@ -40,14 +39,30 @@ public QuizTemplate() { @Override public BaseAdapter newTemplateEditorAdapter(Context context) { mAdapter = new QuizAdapter(context, quizData); + setEmptyView((Activity) context); return mAdapter; } + @Override + public BaseAdapter newMetaEditorAdapter(Context context) { + return null; + } + @Override public BaseAdapter currentTemplateEditorAdapter() { return mAdapter; } + @Override + public BaseAdapter currentMetaEditorAdapter() { + return null; + } + + @Override + public BaseAdapter loadProjectMetaEditor(Context context, Document doc) { + return null; + } + @Override public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList data) { quizData = new ArrayList<>(); @@ -63,6 +78,7 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList } mAdapter = new QuizAdapter(context, quizData); + setEmptyView((Activity) context); return mAdapter; } @@ -147,6 +163,7 @@ public void onClick(View v) { } String questionText = question.getText().toString(); quizData.add(new QuizModel(questionText, answerOptions, correctAnswer)); + setEmptyView(activity); mAdapter.notifyDataSetChanged(); } @@ -156,6 +173,11 @@ public void onClick(View v) { } + @Override + public void addMetaData(Activity activity) { + + } + @Override public void editItem(final Activity activity, final int position) { QuizModel data = quizData.get(position); @@ -245,8 +267,9 @@ public void onClick(View v) { } @Override - public void deleteItem(int position) { + public void deleteItem(Activity activity, int position) { quizData.remove(position); + setEmptyView(activity); mAdapter.notifyDataSetChanged(); } @@ -266,7 +289,7 @@ public ArrayList getItems(Document doc) { } @Override - public Fragment getSimulatorFragment(String filePathWithName) { + public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { return TFTQuizFragment.newInstance(filePathWithName); } @@ -317,4 +340,15 @@ private int getCheckedAnswer(ArrayList buttons) { return -1; } + /** + * @brief Toggles the visibility of empty text if Array has zero elements + */ + @Override + public void setEmptyView(Activity activity) { + if (quizData.size() < 1) { + activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); + } else { + activity.findViewById(R.id.empty).setVisibility(View.GONE); + } + } } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoCollectionAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoCollectionAdapter.java new file mode 100644 index 00000000..a529b5d1 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoCollectionAdapter.java @@ -0,0 +1,90 @@ +package org.buildmlearn.toolkit.templates; + +import android.content.Context; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; + +import com.squareup.picasso.Picasso; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.utilities.RoundedTransformation; +import org.buildmlearn.toolkit.views.TextViewPlus; + +import java.util.ArrayList; + +/** + * @brief Adapter for displaying VideoCollection Template Editor data. + *

+ * Created by Anupam (opticod) on 4/5/16. + */ +class VideoCollectionAdapter extends BaseAdapter { + + private final Context mContext; + private final ArrayList data; + + public VideoCollectionAdapter(Context mContext, ArrayList data) { + this.mContext = mContext; + this.data = data; + } + + @Override + public int getCount() { + return data.size(); + } + + @Override + public VideoModel getItem(int position) { + return data.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + + VideoTemplateHolder holder; + + if (convertView == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + convertView = inflater.inflate(R.layout.video_template_item, parent, false); + holder = new VideoTemplateHolder(); + } else { + holder = (VideoTemplateHolder) convertView.getTag(); + } + + holder.thumb = (ImageView) convertView.findViewById(R.id.thumb); + holder.title = (TextViewPlus) convertView.findViewById(R.id.title); + holder.description = (TextViewPlus) convertView.findViewById(R.id.description); + + VideoModel video = getItem(position); + holder.description.setText(Html.fromHtml("" + "Description : " + " " + video.getDescription())); + holder.title.setText(Html.fromHtml("" + "Title : " + " " + video.getTitle())); + + if (video.getThumbnail_url().length() > 0) { + Picasso + .with(mContext) + .load(video.getThumbnail_url()) + .transform(new RoundedTransformation(20, 20)) + .fit() + .centerCrop() + .into(holder.thumb); + holder.thumb.setAdjustViewBounds(true); + } + + convertView.setTag(holder); + return convertView; + } + + public class VideoTemplateHolder { + public ImageView thumb; + public TextViewPlus title; + public TextViewPlus description; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoCollectionTemplate.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoCollectionTemplate.java new file mode 100644 index 00000000..afd3399b --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoCollectionTemplate.java @@ -0,0 +1,508 @@ +package org.buildmlearn.toolkit.templates; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.view.View; +import android.widget.BaseAdapter; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Toast; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import com.squareup.picasso.Picasso; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.model.TemplateInterface; +import org.buildmlearn.toolkit.utilities.NetworkUtils; +import org.buildmlearn.toolkit.utilities.RoundedTransformation; +import org.buildmlearn.toolkit.videocollectiontemplate.fragment.SplashFragment; +import org.json.JSONException; +import org.json.JSONObject; +import org.jsoup.Jsoup; +import org.jsoup.select.Elements; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; + +/** + * Created by Anupam (opticod) on 4/5/16. + */ +public class VideoCollectionTemplate implements TemplateInterface { + + private static final String YOUTUBE = "youtube"; + private static final String YOUTUBE_SHORT = "youtu.be"; + private static final String DAILYMOTION = "dailymotion"; + private static final String VIMEO = "vimeo"; + private final String TEMPLATE_NAME = "VideoCollection Template"; + transient private VideoCollectionAdapter adapter; + private ArrayList videoData; + transient private ProgressDialog progress; + transient private Context mContext; + + + public VideoCollectionTemplate() { + videoData = new ArrayList<>(); + } + + private static boolean validated(Context context, EditText link) { + if (link == null) { + return false; + } + + String linkText = link.getText().toString(); + + if (linkText.equals("")) { + Toast.makeText(context, R.string.video_collection_template_link_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (!(linkText.contains(YOUTUBE + ".com") || linkText.contains(YOUTUBE_SHORT) || linkText.contains(DAILYMOTION + ".com") || linkText.contains(VIMEO + ".com"))) { + Toast.makeText(context, R.string.video_support_error, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + + } + + private static boolean validated(Context context, EditText title, EditText description, EditText link) { + if (link == null || title == null || description == null) { + return false; + } + + String titleText = title.getText().toString(); + String descriptionText = description.getText().toString(); + String linkText = link.getText().toString(); + + if (titleText.equals("")) { + Toast.makeText(context, R.string.video_collection_template_title_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (descriptionText.equals("")) { + Toast.makeText(context, R.string.video_collection_template_description_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (linkText.equals("")) { + Toast.makeText(context, R.string.video_collection_template_link_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (!(linkText.contains(YOUTUBE + ".com") || linkText.contains(YOUTUBE_SHORT) || linkText.contains(DAILYMOTION + ".com") || linkText.contains(VIMEO + ".com"))) { + Toast.makeText(context, R.string.video_support_error, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + + } + + @Override + public BaseAdapter newTemplateEditorAdapter(Context context) { + mContext = context; + adapter = new VideoCollectionAdapter(context, videoData); + setEmptyView((Activity) context); + return adapter; + } + + @Override + public BaseAdapter newMetaEditorAdapter(Context context) { + return null; + } + + @Override + public BaseAdapter currentTemplateEditorAdapter() { + return adapter; + } + + @Override + public BaseAdapter currentMetaEditorAdapter() { + return null; + } + + @Override + public BaseAdapter loadProjectMetaEditor(Context context, Document doc) { + return null; + } + + @Override + public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList data) { + mContext = context; + videoData = new ArrayList<>(); + for (Element item : data) { + String videoTitle = item.getElementsByTagName(VideoModel.TITLE_TAG).item(0).getTextContent(); + String videoDescription = item.getElementsByTagName(VideoModel.DESCRIPTION_TAG).item(0).getTextContent(); + String videoLink = item.getElementsByTagName(VideoModel.LINK_TAG).item(0).getTextContent(); + String videoThumbLink = item.getElementsByTagName(VideoModel.THUMB_LINK_TAG).item(0).getTextContent(); + videoData.add(new VideoModel(videoTitle, videoDescription, videoLink, videoThumbLink)); + } + adapter = new VideoCollectionAdapter(context, videoData); + setEmptyView((Activity) context); + return adapter; + } + + @Override + public String onAttach() { + return TEMPLATE_NAME; + } + + @Override + public String getTitle() { + return TEMPLATE_NAME; + } + + private String convertLink(String link) { + + if (link.contains(YOUTUBE)) { + if (!link.contains("www.")) { + link = "https://www." + link; + } else if (!(link.contains("http:") || link.contains("https:"))) { + link = "https://" + link; + } + return link; + + } else if (link.contains(YOUTUBE_SHORT)) { + int pos = link.indexOf("youtu.be/"); + link = "https://www.youtube.com/watch?v=" + link.substring(pos + 9); + return link; + + } else if (link.contains(DAILYMOTION)) { + if (!link.contains("www.")) { + link = "https://www." + link; + } else if (!(link.contains("http:") || link.contains("https:"))) { + link = "https://" + link; + } + + String DAILYMOTION_OEMBED_LINK = "http://www.dailymotion.com/services/oembed?url="; + return DAILYMOTION_OEMBED_LINK + link; + + } else if (link.contains(VIMEO)) { + if (!(link.contains("http:") || link.contains("https:"))) { + link = "https://" + link; + } + + String VIMEO_OEMBED_LINK = "https://vimeo.com/api/oembed.json?url="; + return VIMEO_OEMBED_LINK + link; + } + + return null; + } + + @Override + public void addItem(final Activity activity) { + + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.info_add_new_title) + .customView(R.layout.video_dialog_add_data, true) + .positiveText(R.string.info_template_add) + .negativeText(R.string.info_template_cancel) + .build(); + + final EditText link = (EditText) dialog.findViewById(R.id.video_link); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (validated(activity, link)) { + String linkText = link.getText().toString(); + String convertedLink = convertLink(linkText); + + if (NetworkUtils.isNetworkAvailable(mContext)) { + progress = new ProgressDialog(activity); + progress.setCancelable(false); + progress.show(); + new VideoInfoTask().execute(convertedLink, linkText, "-1"); + } else { + Toast.makeText(mContext, R.string.network_error, Toast.LENGTH_SHORT).show(); + } + + dialog.dismiss(); + } + + } + }); + + dialog.show(); + + } + + @Override + public void addMetaData(Activity activity) { + + } + + @Override + public void editItem(final Activity activity, final int position) { + + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.info_edit_title) + .customView(R.layout.video_dialog_edit_data, true) + .positiveText(R.string.info_template_ok) + .negativeText(R.string.info_template_cancel) + .build(); + + final VideoModel data = videoData.get(position); + + final ImageView thumb = (ImageView) dialog.findViewById(R.id.thumb); + final EditText title = (EditText) dialog.findViewById(R.id.video_title); + final EditText description = (EditText) dialog.findViewById(R.id.video_description); + final EditText link = (EditText) dialog.findViewById(R.id.video_link); + + Picasso + .with(mContext) + .load(data.getThumbnail_url()) + .transform(new RoundedTransformation(10, 10)) + .fit() + .centerCrop() + .into(thumb); + + thumb.setAdjustViewBounds(true); + + title.setText(data.getTitle()); + description.setText(data.getDescription()); + link.setText(data.getLink()); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (validated(activity, title, description, link)) { + + String titleText = title.getText().toString(); + String descriptionText = description.getText().toString(); + String linkText = link.getText().toString(); + + setEmptyView(activity); + + if (linkText.equals(data.getLink())) { + data.setTitle(titleText); + data.setDescription(descriptionText); + adapter.notifyDataSetChanged(); + + } else { + String convertedLink = convertLink(linkText); + + if (NetworkUtils.isNetworkAvailable(mContext)) { + progress = new ProgressDialog(activity); + progress.setCancelable(false); + progress.show(); + new VideoInfoTask().execute(convertedLink, linkText, String.valueOf(position)); + } else { + Toast.makeText(mContext, R.string.network_error, Toast.LENGTH_SHORT).show(); + } + } + + dialog.dismiss(); + } + + } + }); + + dialog.show(); + + } + + @Override + public void deleteItem(Activity activity, int position) { + videoData.remove(position); + setEmptyView(activity); + adapter.notifyDataSetChanged(); + } + + @Override + public ArrayList getItems(Document doc) { + ArrayList itemElements = new ArrayList<>(); + + for (VideoModel data : videoData) { + + itemElements.add(data.getXml(doc)); + } + + return itemElements; + } + + @Override + public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { + return SplashFragment.newInstance(filePathWithName); + } + + @Override + public String getAssetsFileName() { + return "video_content.xml"; + } + + @Override + public String getAssetsFilePath() { + return "assets/"; + } + + @Override + public String getApkFilePath() { + return "VideoCollectionApp.apk"; + } + + @Override + public void onActivityResult(Context context, int requestCode, int resultCode, Intent intent) { + + } + + /** + * @brief Toggles the visibility of empty text if Array has zero elements + */ + @Override + public void setEmptyView(Activity activity) { + if (videoData.size() < 1) { + activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); + } else { + activity.findViewById(R.id.empty).setVisibility(View.GONE); + } + } + + private class VideoInfoTask extends AsyncTask { + + String link; + String position; + boolean success; + + @Override + protected String doInBackground(String... params) { + + HttpURLConnection urlConnection = null; + BufferedReader reader = null; + String jsonStr = null; + link = params[1]; + position = params[2]; + success = true; + final String BASE_URL = params[0]; + + if (BASE_URL.contains(YOUTUBE + ".com")) { + try { + int TIMEOUT_LIMIT = 60000; + String USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36"; + org.jsoup.nodes.Document document = Jsoup.connect(BASE_URL) + .timeout(TIMEOUT_LIMIT) + .userAgent(USER_AGENT) + .ignoreContentType(true) + .get(); + + String META_PROPERTY_TITLE = "meta[property=og:title]"; + Elements titleElem = document.select(META_PROPERTY_TITLE); + String META_CONTENT = "content"; + String title = titleElem.attr(META_CONTENT); + + org.jsoup.nodes.Element inputElements = document.getElementById("watch-description-text"); + String description = inputElements.html(); + + //String META_PROPERTY_DESCRIPTION = "meta[property=og:description]"; + //Elements descriptionElem = document.select(META_PROPERTY_DESCRIPTION); + //String description = descriptionElem.attr(META_CONTENT); + + String META_PROPERTY_THUMBNAIL_URL = "meta[property=og:image]"; + Elements thumbnailElem = document.select(META_PROPERTY_THUMBNAIL_URL); + String thumbnail_url = thumbnailElem.attr(META_CONTENT); + + if (position.equals("-1")) { + VideoModel temp = new VideoModel(title, description, BASE_URL, thumbnail_url); + videoData.add(temp); + } else { + VideoModel data = videoData.get(Integer.parseInt(position)); + data.setTitle(title); + data.setDescription(description); + data.setLink(link); + data.setThumbnail_url(thumbnail_url); + } + + } catch (Exception e) { + success = false; + } + } else { + try { + + Uri builtUri = Uri.parse(BASE_URL).buildUpon().build(); + URL url = new URL(builtUri.toString()); + urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setRequestMethod("GET"); + urlConnection.connect(); + InputStream inputStream = urlConnection.getInputStream(); + StringBuilder buffer = new StringBuilder(); + if (inputStream == null) { + success = false; + return null; + } + reader = new BufferedReader(new InputStreamReader(inputStream)); + String line; + while ((line = reader.readLine()) != null) { + buffer.append(line).append("\n"); + } + if (buffer.length() == 0) { + return null; + } + jsonStr = buffer.toString(); + } catch (IOException e) { + success = false; + return null; + } finally { + if (urlConnection != null) { + urlConnection.disconnect(); + } + if (reader != null) { + try { + reader.close(); + } catch (final IOException ignored) { + } + } + } + + return jsonStr; + } + return "done"; + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + + if (result == null) { + Toast.makeText(mContext, R.string.video_fetching_error, Toast.LENGTH_SHORT).show(); + progress.dismiss(); + return; + } + + if (!result.equals("done")) { + + try { + JSONObject json = new JSONObject(result); + String JSON_TITLE = "title"; + String title = json.getString(JSON_TITLE); + String JSON_DESCRIPTION = "description"; + String description = json.getString(JSON_DESCRIPTION); + String JSON_THUMBNAIL_URL = "thumbnail_url"; + String thumbnail_url = json.getString(JSON_THUMBNAIL_URL); + + if (position.equals("-1")) { + VideoModel temp = new VideoModel(title, description, link, thumbnail_url); + videoData.add(temp); + } else { + VideoModel data = videoData.get(Integer.parseInt(position)); + data.setTitle(title); + data.setDescription(description); + data.setLink(link); + data.setThumbnail_url(thumbnail_url); + } + + } catch (JSONException e) { + success = false; + } + } + if (!success) { + Toast.makeText(mContext, R.string.video_fetching_error, Toast.LENGTH_SHORT).show(); + } + adapter.notifyDataSetChanged(); + progress.dismiss(); + } + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoModel.java new file mode 100644 index 00000000..831ed513 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/VideoModel.java @@ -0,0 +1,80 @@ +package org.buildmlearn.toolkit.templates; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.Serializable; + +/** + * @brief Model class for VideoCollection Template Editor data + *

+ * Created by Anupam (opticod) on 4/5/16. + */ +public class VideoModel implements Serializable { + + public static final String TITLE_TAG = "video_title"; + public static final String DESCRIPTION_TAG = "video_description"; + public static final String LINK_TAG = "video_link"; + public static final String THUMB_LINK_TAG = "video_thumb_link"; + private static final String ROOT_TAG = "item"; + private String title; + private String description; + private String link; + private String thumbnail_url; + + public VideoModel(String title, String description, String link, String thumbnail_url) { + this.title = title; + this.description = description; + this.link = link; + this.thumbnail_url = thumbnail_url; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getThumbnail_url() { + return thumbnail_url; + } + + public void setThumbnail_url(String thumbnail_url) { + this.thumbnail_url = thumbnail_url; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + public Element getXml(Document doc) { + Element rootElement = doc.createElement(ROOT_TAG); + Element titleElement = doc.createElement(TITLE_TAG); + titleElement.appendChild(doc.createTextNode(title)); + rootElement.appendChild(titleElement); + Element descriptionElement = doc.createElement(DESCRIPTION_TAG); + descriptionElement.appendChild(doc.createTextNode(String.valueOf(description))); + rootElement.appendChild(descriptionElement); + Element linkElement = doc.createElement(LINK_TAG); + linkElement.appendChild(doc.createTextNode(String.valueOf(link))); + rootElement.appendChild(linkElement); + Element videoLinkElement = doc.createElement(THUMB_LINK_TAG); + videoLinkElement.appendChild(doc.createTextNode(String.valueOf(thumbnail_url))); + rootElement.appendChild(videoLinkElement); + return rootElement; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Alias.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Alias.java index c83ee73c..14d28d84 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Alias.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Alias.java @@ -3,15 +3,15 @@ /** * @brief Model class for storing Alias data for keystore. */ -public class Alias { +class Alias { - long id; - Keystore keystore; - String name; - String displayName; - String password; - boolean selected; - boolean rememberPassword; + private long id; + private Keystore keystore; + private String name; + private String displayName; + private String password; + private boolean selected; + private boolean rememberPassword; public long getId() { return id; @@ -76,9 +76,8 @@ public boolean equals(Object o) { Alias alias = (Alias) o; - if (id != alias.id) return false; + return id == alias.id; - return true; } @Override diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/FileDialog.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/FileDialog.java new file mode 100644 index 00000000..2e8f84bc --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/FileDialog.java @@ -0,0 +1,131 @@ +package org.buildmlearn.toolkit.utilities; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; + +import org.buildmlearn.toolkit.ToolkitApplication; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Created by Anupam (opticod) on 30/5/16. + */ +public class FileDialog { + + private static final String PARENT_DIR = ".."; + private final Activity activity; + private final ListenerList fileListenerList = new ListenerList<>(); + private String[] fileList; + private File currentPath; + private String fileEndsWith; + + public FileDialog(Activity activity) { + this.activity = activity; + loadFileList(new ToolkitApplication().getDir()); + } + + private Dialog createFileDialog() { + Dialog dialog; + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + + builder.setTitle(currentPath.getPath()); + + builder.setItems(fileList, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String fileChosen = fileList[which]; + File chosenFile = getChosenFile(fileChosen); + if (chosenFile.isDirectory()) { + loadFileList(chosenFile); + dialog.cancel(); + dialog.dismiss(); + showDialog(); + } else fireFileSelectedEvent(chosenFile); + } + }); + + dialog = builder.show(); + return dialog; + } + + public void addFileListener(FileSelectListener listener) { + fileListenerList.add(listener); + } + + public void showDialog() { + createFileDialog().show(); + } + + private void fireFileSelectedEvent(final File file) { + fileListenerList.fireEvent(new ListenerList.FireHandler() { + public void fireEvent(FileSelectListener listener) { + listener.fileSelected(file); + } + }); + } + + private void loadFileList(File path) { + this.currentPath = path; + List r = new ArrayList<>(); + if (path.exists()) { + if (path.getParentFile() != null) r.add(PARENT_DIR); + FilenameFilter filter = new FilenameFilter() { + public boolean accept(File dir, String filename) { + File sel = new File(dir, filename); + if (!sel.canRead()) return false; + else { + boolean endsWith = fileEndsWith != null ? filename.toLowerCase().endsWith(fileEndsWith) : true; + return endsWith || sel.isDirectory(); + } + } + }; + String[] fileList1 = path.list(filter); + if (fileList1 == null) { + return; + } + Collections.addAll(r, fileList1); + } + fileList = r.toArray(new String[r.size()]); + } + + private File getChosenFile(String fileChosen) { + if (fileChosen.equals(PARENT_DIR)) return currentPath.getParentFile(); + else return new File(currentPath, fileChosen); + } + + public void setFileEndsWith(String fileEndsWith) { + this.fileEndsWith = fileEndsWith != null ? fileEndsWith.toLowerCase() : fileEndsWith; + } + + public interface FileSelectListener { + void fileSelected(File file); + } +} + +class ListenerList { + private final List listenerList = new ArrayList<>(); + + public void add(L listener) { + listenerList.add(listener); + } + + public void fireEvent(FireHandler fireHandler) { + List copy = new ArrayList<>(listenerList); + for (L l : copy) { + fireHandler.fireEvent(l); + } + } + + public void remove(L listener) { + listenerList.remove(listener); + } + + public interface FireHandler { + void fireEvent(L listener); + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/FileUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/FileUtils.java index 3a169035..7af8e58b 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/FileUtils.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/FileUtils.java @@ -9,7 +9,6 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -21,7 +20,6 @@ import java.util.zip.ZipOutputStream; import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; @@ -34,7 +32,6 @@ */ public class FileUtils { - private final static String TAG = "ZIP_UTIL"; private final static int BUFFER_SIZE = 2048; @@ -45,7 +42,7 @@ public class FileUtils { * @param destinationFolder Destination folder for stroing the uncompresses files. * @throws IOException Exception thrown in case of some error. */ - public static void unZip(String zipFilePath, String destinationFolder) throws IOException { + public static void unZip(String zipFilePath, String destinationFolder) { int size; byte[] buffer = new byte[BUFFER_SIZE]; try { @@ -71,10 +68,8 @@ public static void unZip(String zipFilePath, String destinationFolder) throws IO } else { File parentDir = unzipFile.getParentFile(); - if (null != parentDir) { - if (!parentDir.isDirectory()) { + if (null != parentDir && !parentDir.isDirectory()) { parentDir.mkdirs(); - } } FileOutputStream out = new FileOutputStream(unzipFile, false); @@ -111,13 +106,12 @@ public static void copyAssets(Context context, String assetFileName, String dest OutputStream out; try { in = assetManager.open(assetFileName); - String outPutPath = destinationDirectory; - File f = new File(outPutPath); + File f = new File(destinationDirectory); if (!f.isDirectory()) { f.mkdirs(); } - File outFile = new File(outPutPath, assetFileName); + File outFile = new File(destinationDirectory, assetFileName); out = new FileOutputStream(outFile); copyFile(in, out); in.close(); @@ -144,7 +138,7 @@ private static void copyFile(InputStream in, OutputStream out) throws IOExceptio * @param doc Document object to be converted to xml formatted file * @return Returns true if successfully converted */ - public static boolean saveXmlFile(String destinationFolder, String fileName, Document doc) { + public static void saveXmlFile(String destinationFolder, String fileName, Document doc) { File f = new File(destinationFolder); if (!f.isDirectory()) { @@ -157,13 +151,9 @@ public static boolean saveXmlFile(String destinationFolder, String fileName, Doc DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(new File(destinationFolder + fileName)); transformer.transform(source, result); - return true; - } catch (TransformerConfigurationException e) { - e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } - return false; } /** @@ -174,7 +164,7 @@ public static boolean saveXmlFile(String destinationFolder, String fileName, Doc public static void zipFolder(String directoryToZipPath) throws IOException { File directoryToZip = new File(directoryToZipPath); - List fileList = new ArrayList(); + List fileList = new ArrayList<>(); System.out.println("---Getting references to all files in: " + directoryToZip.getCanonicalPath()); getAllFiles(directoryToZip, fileList); System.out.println("---Creating zip file"); @@ -187,7 +177,7 @@ public static void zipFolder(String directoryToZipPath) throws IOException { * @param dir Source directory * @param fileList Referenced list. Files are added to this list */ - public static void getAllFiles(File dir, List fileList) { + private static void getAllFiles(File dir, List fileList) { try { File[] files = dir.listFiles(); for (File file : files) { @@ -218,14 +208,12 @@ private static void writeZipFile(File directoryToZip, List fileList) { zos.close(); fos.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } - private static void addToZip(File directoryToZip, File file, ZipOutputStream zos) throws FileNotFoundException, + private static void addToZip(File directoryToZip, File file, ZipOutputStream zos) throws IOException { FileInputStream fis = new FileInputStream(file); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/KeyboardHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/KeyboardHelper.java new file mode 100644 index 00000000..702bb772 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/KeyboardHelper.java @@ -0,0 +1,27 @@ +package org.buildmlearn.toolkit.utilities; + +import android.app.Activity; +import android.view.MotionEvent; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +/** + * User : opticod(Anupam Das) + * Date : 24/2/16. + */ +public class KeyboardHelper { + public static void hideKeyboard(final Activity activity, View view) { + view.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + View view = activity.getCurrentFocus(); + if (view != null) { + InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + return false; + } + }); + } +} + diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Keystore.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Keystore.java index d7d85527..7c00216b 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Keystore.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Keystore.java @@ -9,12 +9,11 @@ */ public class Keystore { - long id; - String path; - String password; - boolean rememberPassword; - - List aliases = new ArrayList(); + private final List aliases = new ArrayList<>(); + private long id; + private String path; + private String password; + private boolean rememberPassword; public long getId() { return id; @@ -63,9 +62,8 @@ public boolean equals(Object o) { Keystore keystore = (Keystore) o; - if (id != keystore.id) return false; + return id == keystore.id; - return true; } @Override diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/NetworkUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/NetworkUtils.java new file mode 100644 index 00000000..887f67f2 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/NetworkUtils.java @@ -0,0 +1,17 @@ +package org.buildmlearn.toolkit.utilities; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * Created by Anupam(opticod) on 10/5/16. + */ +public class NetworkUtils { + public static boolean isNetworkAvailable(Context mContext) { + ConnectivityManager connectivityManager + = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); + return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting(); + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/RoundedTransformation.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/RoundedTransformation.java new file mode 100644 index 00000000..581a475a --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/RoundedTransformation.java @@ -0,0 +1,47 @@ +package org.buildmlearn.toolkit.utilities; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; + +// enables hardware accelerated rounded corners +// original idea here : http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/ +public class RoundedTransformation implements com.squareup.picasso.Transformation { + private final int radius; + private final int margin; // dp + private final String key; + + // radius is corner radii in dp + // margin is the board in dp + public RoundedTransformation(final int radius, final int margin) { + this.radius = radius; + this.margin = margin; + this.key = "rounded(radius=" + radius + ", margin=" + margin + ")"; + } + + @Override + public Bitmap transform(final Bitmap source) { + final Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + + Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888); + Canvas canvas = new Canvas(output); + canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint); + + if (source != output) { + source.recycle(); + } + + return output; + } + + @Override + public String key() { + return this.key; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/SignerThread.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/SignerThread.java index d47ad79f..2d5f4123 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/SignerThread.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/SignerThread.java @@ -1,8 +1,42 @@ +/* + * + * Reference :: https://github.com/sjitech/ApkRename/tree/master/lib/AndroidManifestBinaryXml_ChangePackageName + * + * Library Name :: axml.jar + * + * The MIT License (MIT) + * + * Copyright (c) 2014 SJI Research Center for Advanced Technology + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + package org.buildmlearn.toolkit.utilities; +import android.Manifest; import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.provider.Settings.Secure; import android.support.v4.app.NotificationCompat; +import android.support.v4.content.ContextCompat; import android.util.Log; import android.widget.Toast; @@ -11,16 +45,26 @@ import org.buildmlearn.toolkit.model.KeyStoreDetails; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; import java.security.UnrecoverableKeyException; +import java.util.Calendar; import kellinwood.security.zipsigner.AutoKeyException; import kellinwood.security.zipsigner.ZipSigner; import kellinwood.security.zipsigner.optional.CustomKeySigner; +import pxb.android.axml.AxmlReader; +import pxb.android.axml.AxmlVisitor; +import pxb.android.axml.AxmlWriter; +import pxb.android.axml.NodeVisitor; /** * Created by Abhishek on 10-06-2015. + * Modified by Anupam (opticod) on 18-05-2016 */ /** @@ -29,16 +73,19 @@ public class SignerThread extends Thread { private static final String TAG = "SignerThread"; private static final String TEMP_FOLDER = "hcjb"; - ZipSigner zipSigner = null; - String signatureAlgorithm = "SHA1withRSA"; - private ToolkitApplication toolkit; - private Context context; - private String assetsApk; + private static final String NS = "http://schemas.android.com/apk/res/android"; + private static boolean needRemoveConflict; + private static boolean needRemoveLib; + private static String newPackageFullName; + private static boolean changed; + private final ToolkitApplication toolkit; + private final Context context; + private final String assetsApk; + private final String assetFileName; + private final String assetFilePath; + private final String projectFile; + private final KeyStoreDetails keyDetails; private String finalApk; - private String assetFileName; - private String assetFilePath; - private String projectFile; - private KeyStoreDetails keyDetails; private OnSignComplete listener; public SignerThread(Context context, String assetsApk, String finalApk, KeyStoreDetails keyDetails, String assetFilePath, String assetFileName) { @@ -52,35 +99,81 @@ public SignerThread(Context context, String assetsApk, String finalApk, KeyStore this.assetFilePath = assetFilePath; } + + private static void modifyManifest(final String[] args) { + try { + String androidManifestBinXml = args[0]; + needRemoveConflict = args[1].contains("!"); + needRemoveLib = args[1].contains("%"); + newPackageFullName = args[1].replace("!", "").replace("%", ""); + InputStream is = new FileInputStream(androidManifestBinXml); + byte[] xml = new byte[is.available()]; + is.read(xml); + is.close(); + AxmlReader ar = new AxmlReader(xml); + AxmlWriter aw = new AxmlWriter(); + ar.accept(new AxmlVisitor(aw) { + @Override + public NodeVisitor child(String ns, String name) { + return new MyNodeVisitor(super.child(ns, name), name); + } + }); + + if (changed) { + byte[] modified = aw.toByteArray(); + FileOutputStream fos = new FileOutputStream(androidManifestBinXml); + fos.write(modified); + fos.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + public void setSignerThreadListener(OnSignComplete listener) { this.listener = listener; } public void run() { + int permissionCheck = ContextCompat.checkSelfPermission(context, + Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (permissionCheck == -1) { + listener.onFail(new FileNotFoundException()); + return; + } + FileUtils.copyAssets(context, assetsApk, toolkit.getApkDir()); FileUtils.copyAssets(context, keyDetails.getAssetsPath(), toolkit.getApkDir()); + FileUtils.unZip(toolkit.getApkDir() + assetsApk, toolkit.getUnZipDir() + TEMP_FOLDER); try { - FileUtils.unZip(toolkit.getApkDir() + assetsApk, toolkit.getUnZipDir() + TEMP_FOLDER); - } catch (IOException e) { + String packageName = "org.buildmlearn.app"; + packageName += Secure.getString(context.getContentResolver(), + Secure.ANDROID_ID); + Calendar rightNow = Calendar.getInstance(); + packageName += String.valueOf(rightNow.getTimeInMillis()); + + modifyManifest(new String[]{toolkit.getUnZipDir() + TEMP_FOLDER + "/AndroidManifest.xml", packageName}); + } catch (Exception e) { if (listener != null) { listener.onFail(e); } e.printStackTrace(); } + File folder = new File(toolkit.getUnZipDir() + TEMP_FOLDER + "/" + assetFilePath); - boolean success = true; + if (!folder.exists()) { - success = folder.mkdir(); + folder.mkdir(); } File src = new File(projectFile); File dest = new File(toolkit.getUnZipDir() + TEMP_FOLDER + "/" + assetFilePath + assetFileName); try { - FileWriter fileWriter = new FileWriter(dest.getAbsoluteFile(), true); + new FileWriter(dest.getAbsoluteFile(), true); } catch (IOException e) { e.printStackTrace(); } @@ -110,7 +203,7 @@ public void run() { throw new IllegalArgumentException("Parameter outputFile is null"); } - zipSigner = new ZipSigner(); + ZipSigner zipSigner = new ZipSigner(); zipSigner.setResourceAdapter(new ZipSignerAppResourceAdapter(context.getResources())); File keystoreFile; @@ -119,11 +212,12 @@ public void run() { char[] keyPass = keyDetails.getPassword().toCharArray(); char[] aliasPass = keyDetails.getAliasPassword().toCharArray(); - if (toolkit.isExternalStorageAvailable()) { + if (toolkit.checkExternalStorage()) { finalApk = toolkit.getDownloadDirectory() + "/" + finalApk.substring(toolkit.getSavedDir().length()); Log.d(TAG, "Final APK: " + finalApk); } + String signatureAlgorithm = "SHA1withRSA"; CustomKeySigner.signZip(zipSigner, keystoreFile.getAbsolutePath(), keyPass, keyDetails.getAlias(), aliasPass, signatureAlgorithm, inputFile, finalApk); @@ -162,11 +256,17 @@ public void run() { } private void showNotification(String description) { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + File file = new File(finalApk); + intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(toolkit) .setSmallIcon(R.drawable.ic_stat_toggle_check_box) .setContentTitle("APK Generated") .setContentText(description) + .setContentIntent(pendingIntent) .setAutoCancel(true); NotificationManager mNotificationManager = @@ -181,5 +281,72 @@ public interface OnSignComplete { void onFail(Exception e); } -} + public static class MyNodeVisitor extends NodeVisitor { + public static String level = ""; + public static String oldPackageName; + public boolean didLogNodeName = false; + public String nodeName = ""; + + MyNodeVisitor(NodeVisitor nv, String nodeName) { + super(nv); + this.nodeName = nodeName; + } + + @Override + public NodeVisitor child(String ns, String name) { + if (needRemoveConflict && ("original-package".equals(name) || "provider".equals(name)) && ns == null) { + changed = true; + return null; + } else if (needRemoveLib && ("uses-library".equals(name)) && ns == null) { + changed = true; + return null; + } + level += " "; + return new MyNodeVisitor(super.child(ns, name), name); + } + + @Override + public void attr(String ns, String name, int resourceId, int type, Object val) { + String oldName = name; + Object oldVal = val; + if (ns == null && "package".equals(name) && "manifest".equals(nodeName) && type == NodeVisitor.TYPE_STRING && level.length() == 0) { + oldPackageName = (String) val; + if (!newPackageFullName.equals(val)) { + val = newPackageFullName; + } + } else if (type == NodeVisitor.TYPE_STRING && ("name".equals(name) || "backupAgent".equals(name) || "manageSpaceActivity".equals(name) || "targetActivity".equals(name)) && NS.equals(ns) && val != null && val instanceof String) { + if (((String) val).startsWith(".")) { + val = oldPackageName + val; + } else if (!((String) val).contains(".") && ((String) val).length() > 0) { + val = oldPackageName + "." + val; + } + } else if (type == NodeVisitor.TYPE_STRING && "value".equals(name) && NS.equals(ns) && val != null && val instanceof String) { + if (((String) val).startsWith(".")) { + val = oldPackageName + val; + } + } else if (needRemoveConflict && ("protectionLevel".equals(name) || "process".equals(name) || "sharedUserId".equals(name)) && NS.equals(ns)) { + name = null; + } else if (needRemoveConflict && ("coreApp".equals(name)) && ns == null) { + name = null; + } + if (name != oldName || val != oldVal) { + changed = true; + if (!didLogNodeName) { + didLogNodeName = true; + } + if (name == null) { + return; + } + } + + super.attr(ns, name, resourceId, type, val); + } + + @Override + public void end() { + level = level.length() > 4 ? level.substring(4) : ""; + super.end(); + } + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/ZipSignerAppResourceAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/ZipSignerAppResourceAdapter.java index 81fe9d8b..1226f1a1 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/ZipSignerAppResourceAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/ZipSignerAppResourceAdapter.java @@ -9,9 +9,9 @@ /** * @brief Provides internationalized progress and error strings to the zipsigner-lib API. */ -public class ZipSignerAppResourceAdapter implements ResourceAdapter { +class ZipSignerAppResourceAdapter implements ResourceAdapter { - Resources resources; + private final Resources resources; public ZipSignerAppResourceAdapter(Resources resources) { this.resources = resources; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/Constants.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/Constants.java new file mode 100644 index 00000000..ba67f2db --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/Constants.java @@ -0,0 +1,22 @@ +package org.buildmlearn.toolkit.videocollectiontemplate; + +import org.buildmlearn.toolkit.videocollectiontemplate.data.VideoContract; + +/** + * Created by Anupam (opticod) on 13/5/16. + */ +public class Constants { + public static final String[] VIDEO_COLUMNS = { + VideoContract.Videos.TABLE_NAME + "." + VideoContract.Videos._ID, + VideoContract.Videos.TITLE, + VideoContract.Videos.DESCRIPTION, + VideoContract.Videos.LINK, + VideoContract.Videos.THUMBNAIL_URL + }; + public static final int COL_ID = 0; + public static final int COL_TITLE = 1; + public static final int COL_DESCRIPTION = 2; + public static final int COL_LINK = 3; + public static final int COL_THUMBNAIL_URL = 4; + public static String XMLFileName = "video_content.xml"; +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/adapter/VideoArrayAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/adapter/VideoArrayAdapter.java new file mode 100644 index 00000000..100248f3 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/adapter/VideoArrayAdapter.java @@ -0,0 +1,92 @@ +package org.buildmlearn.toolkit.videocollectiontemplate.adapter; + +import android.content.Context; +import android.database.Cursor; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.squareup.picasso.Callback; +import com.squareup.picasso.Picasso; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.utilities.RoundedTransformation; +import org.buildmlearn.toolkit.videocollectiontemplate.Constants; + +/** + * Created by Anupam (opticod) on 12/5/16. + */ +public class VideoArrayAdapter extends CursorAdapter { + + public VideoArrayAdapter(Context context) { + super(context, null, 0); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + View view = LayoutInflater.from(context).inflate(R.layout.list_item_video, parent, false); + ViewHolder viewHolder = new ViewHolder(view); + view.setTag(viewHolder); + return view; + } + + /* + * This is where we fill-in the views with the contents of the cursor. + */ + @Override + public void bindView(View view, final Context context, Cursor cursor) { + final ViewHolder viewHolder = (ViewHolder) view.getTag(); + + final String thumb_url = cursor.getString(Constants.COL_THUMBNAIL_URL); + + Picasso + .with(context) + .load(thumb_url) + .transform(new RoundedTransformation(10, 10)) + .fit() + .centerCrop() + .into(viewHolder.thumb, new Callback() { + @Override + public void onSuccess() { + // This constructor is intentionally empty + } + + @Override + public void onError() { + Picasso + .with(context) + .load(thumb_url) + .error(R.mipmap.ic_launcher) + .fit() + .centerCrop() + .into(viewHolder.thumb); + } + }); + + viewHolder.thumb.setAdjustViewBounds(true); + + String title = cursor.getString(Constants.COL_TITLE); + viewHolder.title.setText(title); + + String description = cursor.getString(Constants.COL_DESCRIPTION); + viewHolder.description.setText(Html.fromHtml(description)); + + } + + public static class ViewHolder { + + public final ImageView thumb; + public final TextView title; + public final TextView description; + + public ViewHolder(View view) { + thumb = (ImageView) view.findViewById(R.id.thumb); + title = (TextView) view.findViewById(R.id.title); + description = (TextView) view.findViewById(R.id.description); + } + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/DataUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/DataUtils.java new file mode 100644 index 00000000..dc3680fc --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/DataUtils.java @@ -0,0 +1,44 @@ +package org.buildmlearn.toolkit.videocollectiontemplate.data; + +import org.buildmlearn.toolkit.videocollectiontemplate.Constants; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Created by Anupam (opticod) on 13/5/16. + */ +public class DataUtils { + + public static String[] readTitleAuthor() { + String result[] = new String[2]; + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setValidating(false); + + DocumentBuilder db; + Document doc; + try { + File fXmlFile = new File(Constants.XMLFileName); + db = dbf.newDocumentBuilder(); + doc = db.parse(fXmlFile); + doc.normalize(); + + result[0] = doc.getElementsByTagName("title").item(0).getChildNodes() + .item(0).getNodeValue(); + + result[1] = doc.getElementsByTagName("name").item(0).getChildNodes() + .item(0).getNodeValue(); + + } catch (ParserConfigurationException | SAXException | IOException e) { + e.printStackTrace(); + } + return result; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/FetchXMLTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/FetchXMLTask.java new file mode 100644 index 00000000..13416b0a --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/FetchXMLTask.java @@ -0,0 +1,139 @@ +package org.buildmlearn.toolkit.videocollectiontemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.os.AsyncTask; + +import org.buildmlearn.toolkit.videocollectiontemplate.Constants; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Vector; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Created by Anupam (opticod) on 13/5/16. + */ +public class FetchXMLTask extends AsyncTask { + + private final Context mContext; + + public FetchXMLTask(Context context) { + mContext = context; + } + + private static String getValue(String tag, Element element) { + NodeList nodeList = null; + NodeList node1 = element.getElementsByTagName(tag); + if (node1 != null && node1.getLength() != 0) + nodeList = node1.item(0).getChildNodes(); + if (nodeList == null) + return ""; + else if (nodeList.getLength() == 0) + return ""; + else { + Node node = nodeList.item(0); + return node.getNodeValue(); + } + } + + private void saveVideoData(ArrayList videos) { + + Vector cVVector = new Vector<>(videos.size()); + + for (int i = 0; i < videos.size(); i++) { + + String title; + String description; + String link; + String thumbnail_url; + + VideoModel videoInfo = videos.get(i); + + title = videoInfo.getTitle(); + description = videoInfo.getDescription(); + link = videoInfo.getLink(); + thumbnail_url = videoInfo.getThumbnailUrl(); + + ContentValues videoValues = new ContentValues(); + + videoValues.put(VideoContract.Videos.TITLE, title); + videoValues.put(VideoContract.Videos.DESCRIPTION, description); + videoValues.put(VideoContract.Videos.LINK, link); + videoValues.put(VideoContract.Videos.THUMBNAIL_URL, thumbnail_url); + + cVVector.add(videoValues); + } + // add to database + if (cVVector.size() > 0) { + ContentValues[] cvArray = new ContentValues[cVVector.size()]; + cVVector.toArray(cvArray); + VideoDb db = new VideoDb(mContext); + db.open(); + db.bulkInsert(cvArray); + db.close(); + } + } + + @Override + protected Void doInBackground(String... params) { + + if (params.length == 0) { + return null; + } + ArrayList mList; + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setValidating(false); + + DocumentBuilder db; + Document doc; + try { + File fXmlFile = new File(Constants.XMLFileName); + db = dbf.newDocumentBuilder(); + doc = db.parse(fXmlFile); + doc.normalize(); + mList = new ArrayList<>(); + + NodeList childNodes = doc.getElementsByTagName("item"); + + for (int i = 0; i < childNodes.getLength(); i++) { + VideoModel app = new VideoModel(); + + Node child = childNodes.item(i); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element2 = (Element) child; + + app.setTitle(getValue("video_title", element2)); + app.setDescription(getValue("video_description", element2)); + app.setLink(getValue("video_link", element2)); + app.setThumbnailUrl(getValue("video_thumb_link", element2)); + + } + mList.add(app); + } + saveVideoData(mList); + } catch (ParserConfigurationException e) { + return null; + } catch (FileNotFoundException e) { + return null; + } catch (SAXException e) { + return null; + } catch (IOException e) { + return null; + } + return null; + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoContract.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoContract.java new file mode 100644 index 00000000..fb578880 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoContract.java @@ -0,0 +1,21 @@ +package org.buildmlearn.toolkit.videocollectiontemplate.data; + +import android.provider.BaseColumns; + +/** + * Created by Anupam (opticod) on 13/5/16. + */ + +public class VideoContract { + + public static final class Videos implements BaseColumns { + + public static final String TABLE_NAME = "videos"; + + public static final String TITLE = "title"; + public static final String DESCRIPTION = "description"; + public static final String LINK = "link"; + public static final String THUMBNAIL_URL = "thumbnail_url"; + + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoDBHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoDBHelper.java new file mode 100644 index 00000000..2f4e8be9 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoDBHelper.java @@ -0,0 +1,39 @@ +package org.buildmlearn.toolkit.videocollectiontemplate.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.buildmlearn.toolkit.videocollectiontemplate.data.VideoContract.Videos; + +/** + * Created by Anupam (opticod) on 13/5/16. + */ + +class VideoDBHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "video.db"; + private static final int DATABASE_VERSION = 1; + + public VideoDBHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + final String SQL_CREATE__TABLE = "CREATE TABLE " + Videos.TABLE_NAME + " (" + + Videos._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Videos.TITLE + " TEXT," + + Videos.DESCRIPTION + " TEXT," + + Videos.LINK + " TEXT," + + Videos.THUMBNAIL_URL + " TEXT)"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE); + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Videos.TABLE_NAME); + onCreate(sqLiteDatabase); + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoDb.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoDb.java new file mode 100644 index 00000000..513eeafc --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoDb.java @@ -0,0 +1,93 @@ +package org.buildmlearn.toolkit.videocollectiontemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.support.annotation.NonNull; + +/** + * Created by Anupam (opticod) on 19/5/16. + */ +public class VideoDb { + + private static final String EQUAL = " == "; + private final VideoDBHelper dbHelper; + private SQLiteDatabase db; + + public VideoDb(Context context) { + dbHelper = new VideoDBHelper(context); + } + + public void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public boolean isOpen() { + return db.isOpen(); + } + + public void close() { + dbHelper.close(); + } + + public Cursor getVideosCursor() { + + return db.query( + VideoContract.Videos.TABLE_NAME, + null, + null, + null, + null, + null, + null + ); + } + + public Cursor getVideoCursorById(int id) { + + String selection = VideoContract.Videos._ID + EQUAL + id; + + return db.query( + VideoContract.Videos.TABLE_NAME, + null, + selection, + null, + null, + null, + null + ); + } + + public long getCount() { + + return DatabaseUtils.queryNumEntries(db, + VideoContract.Videos.TABLE_NAME); + } + + public void deleteAll() { + db.delete(VideoContract.Videos.TABLE_NAME, null, null); + db.execSQL("delete from sqlite_sequence where name='" + VideoContract.Videos.TABLE_NAME + "';"); + } + + public int bulkInsert(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(VideoContract.Videos.TABLE_NAME, null, value); + if (_id != -1) { + returnCount++; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + return returnCount; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoModel.java new file mode 100644 index 00000000..538bebb5 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/data/VideoModel.java @@ -0,0 +1,113 @@ +package org.buildmlearn.toolkit.videocollectiontemplate.data; + +import android.os.Parcel; +import android.os.Parcelable; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Created by Anupam (opticod) on 12/5/16. + */ +public class VideoModel implements Parcelable { + private static final String ROOT_TAG = "item"; + private static final String TITLE_TAG = "video_title"; + private static final String DESCRIPTION_TAG = "video_description"; + private static final String LINK_TAG = "video_link"; + private static final String THUMB_LINK_TAG = "video_thumb_link"; + public final Creator CREATOR = new Creator() { + @Override + public VideoModel createFromParcel(Parcel parcel) { + return new VideoModel(parcel); + } + + @Override + public VideoModel[] newArray(int size) { + return new VideoModel[size]; + } + }; + private String title; + private String description; + private String link; + private String thumbnail_url; + + public VideoModel() { + } + + public VideoModel(String title, String description, String link, String thumbnail_url) { + this.title = title; + this.description = description; + this.link = link; + this.thumbnail_url = thumbnail_url; + } + + private VideoModel(Parcel in) { + this.title = in.readString(); + this.description = in.readString(); + this.link = in.readString(); + this.thumbnail_url = in.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(title); + dest.writeString(description); + dest.writeString(link); + dest.writeString(thumbnail_url); + } + + public Element getXml(Document doc) { + Element rootElement = doc.createElement(ROOT_TAG); + Element titleElement = doc.createElement(TITLE_TAG); + titleElement.appendChild(doc.createTextNode(title)); + rootElement.appendChild(titleElement); + Element descriptionElement = doc.createElement(DESCRIPTION_TAG); + descriptionElement.appendChild(doc.createTextNode(String.valueOf(description))); + rootElement.appendChild(descriptionElement); + Element linkElement = doc.createElement(LINK_TAG); + linkElement.appendChild(doc.createTextNode(String.valueOf(link))); + rootElement.appendChild(linkElement); + Element videoLinkElement = doc.createElement(THUMB_LINK_TAG); + videoLinkElement.appendChild(doc.createTextNode(String.valueOf(thumbnail_url))); + rootElement.appendChild(videoLinkElement); + return rootElement; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getThumbnailUrl() { + return thumbnail_url; + } + + public void setThumbnailUrl(String thumbnail_url) { + this.thumbnail_url = thumbnail_url; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/DetailActivityFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/DetailActivityFragment.java new file mode 100644 index 00000000..a41debd2 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/DetailActivityFragment.java @@ -0,0 +1,267 @@ +package org.buildmlearn.toolkit.videocollectiontemplate.fragment; + +import android.app.FragmentManager; +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.Toolbar; +import android.text.Html; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.videocollectiontemplate.Constants; +import org.buildmlearn.toolkit.videocollectiontemplate.data.VideoDb; + +/** + * Created by Anupam (opticod) on 13/5/16. + */ +public class DetailActivityFragment extends Fragment implements LoaderCallbacks { + + private static final int DETAIL_LOADER = 0; + + private View rootView; + private WebView player; + private String video_Id; + private VideoDb db; + + public DetailActivityFragment() { + setHasOptionsMenu(true); + } + + public static Fragment newInstance() { + return new DetailActivityFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + Bundle arguments = getArguments(); + if (arguments != null) { + video_Id = arguments.getString(Intent.EXTRA_TEXT); + } + rootView = inflater.inflate(R.layout.fragment_detail_video, container, false); + + db = new VideoDb(getActivity()); + db.open(); + Toolbar maintoolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + maintoolbar.setTitle(getString(R.string.video_collection_title)); + maintoolbar.inflateMenu(R.menu.menu_main_white); + maintoolbar.setNavigationIcon(R.drawable.ic_home_white_24dp); + + maintoolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), MainActivityFragment.newInstance()).addToBackStack(null).commit(); + } + }); + maintoolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.action_about: + AlertDialog.Builder builder = + new AlertDialog.Builder(getActivity()); + builder.setTitle(String.format("%1$s", getString(R.string.about_us))); + builder.setMessage(getResources().getText(R.string.about_text_video)); + builder.setPositiveButton("OK", null); + AlertDialog welcomeAlert = builder.create(); + welcomeAlert.show(); + assert welcomeAlert.findViewById(android.R.id.message) != null; + assert welcomeAlert.findViewById(android.R.id.message) != null; + ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + break; + default: //do nothing + break; + } + return true; + } + }); + + + return rootView; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + getLoaderManager().initLoader(DETAIL_LOADER, null, this); + super.onActivityCreated(savedInstanceState); + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + if (null != video_Id) { + switch (id) { + case DETAIL_LOADER: + + return new CursorLoader(getActivity(), null, Constants.VIDEO_COLUMNS, null, null, null) { + @Override + public Cursor loadInBackground() { + return db.getVideoCursorById(Integer.parseInt(video_Id)); + } + }; + default: //do nothing + break; + } + } + return null; + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + if (data != null && data.moveToFirst()) { + String title = data.getString(Constants.COL_TITLE); + + ((TextView) rootView.findViewById(R.id.title)) + .setText(title); + + String description = data.getString(Constants.COL_DESCRIPTION); + + ((TextView) rootView.findViewById(R.id.description)) + .setText(Html.fromHtml(description)); + + player = (WebView) rootView.findViewById(R.id.player); + + player.setWebChromeClient(new WebChromeClient()); + player.setWebViewClient(new WebViewClient()); + + player.getSettings().setJavaScriptEnabled(true); + player.getSettings().setAppCacheEnabled(true); + player.getSettings().setDomStorageEnabled(true); + player.getSettings().setAllowFileAccess(true); + player.getSettings().setLoadWithOverviewMode(true); + player.getSettings().setUseWideViewPort(true); + player.getSettings().setTextZoom(140); + + String link = data.getString(Constants.COL_LINK); + if (link.contains("youtube.com")) { + + int pos = link.indexOf("watch?v="); + String videoId = link.substring(pos + 8); + + String playVideo = "" + + "