diff --git a/source-code/app/build.gradle b/source-code/app/build.gradle index 40cc3c61..8c0eb7d7 100644 --- a/source-code/app/build.gradle +++ b/source-code/app/build.gradle @@ -30,8 +30,8 @@ android { applicationId "org.buildmlearn.toolkit" minSdkVersion 14 targetSdkVersion 23 - versionCode 1 - versionName "1.0" + versionCode 2 + versionName "2.0.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } 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 index 2c3a9b5e..50cf5582 100644 --- 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 @@ -56,6 +56,7 @@ import static org.hamcrest.core.IsInstanceOf.instanceOf; /** + * Espresso test designed to test all the functionalities of Comprehension template * Created by anupam (opticod) on 7/6/16. */ diff --git a/source-code/app/src/main/AndroidManifest.xml b/source-code/app/src/main/AndroidManifest.xml index b83612eb..398ced71 100755 --- a/source-code/app/src/main/AndroidManifest.xml +++ b/source-code/app/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" + android:supportsRtl="true" android:theme="@style/AppTheme" > + + + Anupam + + Dictation + + + Dream of the Rarebit Fiend + 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. + + + Earthworks + Bill Bruford's Earthworks were a British jazz band led by drummer Bill Bruford. The band recorded several albums for Editions EG, Discipline Global Mobile and Summerfold Records. + +Earthworks went through several line-ups: in addition to the band's accomplishments as a unit, Earthworks was a training ground for Django Bates, Iain Ballamy, Patrick Clahar, Mark Hodgson, Steve Hamilton and Gwilym Simcock. The final band line-up featured previously established jazz musicians in the form of Chick Corea sideman Tim Garland and veteran bass player Laurence Cottle. In interviews during the band's earlier years, Bruford sometimes compared his responsibilities within it as being similar to those of Art Blakey with the Jazz Messengers, in that he was providing an environment for young British jazz players to gain attention and experience before going on to become well-known players and bandleaders in their own right. + + + diff --git a/source-code/app/src/main/assets/template_assets/match_content.xml b/source-code/app/src/main/assets/template_assets/match_content.xml new file mode 100644 index 00000000..46ff9827 --- /dev/null +++ b/source-code/app/src/main/assets/template_assets/match_content.xml @@ -0,0 +1,38 @@ + + + + Anupam + + Country Match + + + Match the countries + Country + Capital + + + India + New Delhi + + + Bangladesh + Dhaka + + + Malaysia + Kuala Lumpur + + + Pakistan + Islamabad + + + Portugal + Lisbon + + + Syria + Damascus + + + 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 ef0d1170..2b056851 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 @@ -9,6 +9,8 @@ import org.buildmlearn.toolkit.R; +import java.util.Locale; + /** * @brief Gives brief info about BuildmLearn community and toolkit */ @@ -30,9 +32,10 @@ protected void onCreate(Bundle savedInstanceState) { 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); + ((TextView) findViewById(R.id.app_version)).setText(String.format(Locale.ENGLISH, "Version: %s", version)); } catch (PackageManager.NameNotFoundException e) { assert findViewById(R.id.app_version) != null; + assert ((TextView) 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/HomeActivity.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/activity/HomeActivity.java index 8851085d..a9dabb52 100755 --- 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 @@ -22,6 +22,7 @@ public class HomeActivity extends AppCompatActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks { private Section currentSection; + private NavigationDrawerFragment mNavigationDrawerFragment; /** * {@inheritDoc} @@ -37,7 +38,7 @@ protected void onCreate(Bundle savedInstanceState) { /* Fragment managing the behaviors, interactions and presentation of the navigation drawer. */ - NavigationDrawerFragment mNavigationDrawerFragment = (NavigationDrawerFragment) + mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer); // Set up the drawer. @@ -81,7 +82,7 @@ public void onNavigationDrawerItemSelected(int position) { if (currentSection == null || selectedMenuItem != currentSection) { currentSection = selectedMenuItem; FragmentManager fm = getFragmentManager(); - FragmentTransaction ft = fm.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); + FragmentTransaction ft = fm.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).addToBackStack(null); Fragment f = fm.findFragmentById(R.id.container); if (f != null) { if (currentSection.isKeep()) { @@ -104,4 +105,15 @@ public void onNavigationDrawerItemSelected(int position) { } } + @Override + public void onBackPressed() { + if (mNavigationDrawerFragment.isDrawerOpen()) { + mNavigationDrawerFragment.closeDrawer(); + return; + } + if (getFragmentManager().getBackStackEntryCount() <= 1) { + finish(); + } + super.onBackPressed(); + } } 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 43088a46..55e2982e 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 @@ -4,11 +4,9 @@ import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; -import android.view.View; -import android.widget.AbsListView; -import android.widget.AdapterView; -import android.widget.ListAdapter; import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.adapter.TemplateAdapter; @@ -28,20 +26,21 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_template); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); ActionBar actionBar = getSupportActionBar(); + assert actionBar != null; actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeButtonEnabled(true); - ListAdapter mAdapter = new TemplateAdapter(this); - AbsListView mListView = (AbsListView) findViewById(android.R.id.list); - mListView.setAdapter(mAdapter); + TemplateAdapter mAdapter = new TemplateAdapter(this); + RecyclerView mRecyclerView = (RecyclerView) findViewById(android.R.id.list); + assert mRecyclerView != null; + mRecyclerView.setAdapter(mAdapter); + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); - mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + mAdapter.setOnClickListener(new TemplateAdapter.SetOnClickListener() { @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - + public void onItemClick(int position) { Intent intent = new Intent(getApplicationContext(), TemplateEditor.class); 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 74e612a3..bac304a4 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 @@ -127,7 +127,7 @@ protected void onCreate(Bundle savedInstanceState) { findViewById(R.id.button_add_item).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (templateId == 5 && selectedTemplate.currentMetaEditorAdapter().isEmpty()) { + if ((templateId == 5 || templateId == 7) && selectedTemplate.currentMetaEditorAdapter().isEmpty()) { selectedTemplate.addMetaData(TemplateEditor.this); } else { selectedTemplate.addItem(TemplateEditor.this); @@ -301,13 +301,11 @@ private void setUpTemplateEditor() { selectedTemplate = (TemplateInterface) templateObject; selectedTemplate.setTemplateId(templateId); populateListView(selectedTemplate.newTemplateEditorAdapter(this)); - if (templateId == 5) { + if (templateId == 5 || templateId == 7) { populateMetaView(selectedTemplate.newMetaEditorAdapter(this)); } setUpActionBar(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } @@ -325,7 +323,7 @@ private void restoreTemplateEditor(Bundle savedInstanceState) { finish(); } else { populateListView(selectedTemplate.currentTemplateEditorAdapter()); - if (templateId == 5) { + if (templateId == 5 || templateId == 7) { populateMetaView(selectedTemplate.currentMetaEditorAdapter()); } setUpActionBar(); @@ -397,20 +395,36 @@ public void onClick(View v) { new BottomSheet.Builder(this).sheet(R.menu.bottom_sheet_template).listener(new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { + String savedFilePath; switch (id) { case R.id.save_project: saveProject(); break; + + case R.id.share_project: + savedFilePath = saveProject(); + if (savedFilePath == null || savedFilePath.length() == 0) { + return; + } + Uri fileUri = Uri.fromFile(new File(savedFilePath)); + ArrayList uris = new ArrayList<>(); + Intent sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); + sendIntent.setType("application/zip"); + uris.add(fileUri); + sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); + startActivity(Intent.createChooser(sendIntent, null)); + break; + case R.id.share_apk: - String savedFilePath = saveProject(); + savedFilePath = saveProject(); if (savedFilePath == null || savedFilePath.length() == 0) { return; } String keyPassword = getString(R.string.key_password); String aliasName = getString(R.string.alias_name); String aliaspassword = getString(R.string.alias_password); - KeyStoreDetails keyStoreDetails = new KeyStoreDetails("TestKeyStore.jks", keyPassword, aliasName, aliaspassword); + KeyStoreDetails keyStoreDetails = new KeyStoreDetails(keyPassword, aliasName, aliaspassword); SignerThread signer = new SignerThread(getApplicationContext(), selectedTemplate.getApkFilePath(), saveProject(), keyStoreDetails, selectedTemplate.getAssetsFilePath(), selectedTemplate.getAssetsFileName(TemplateEditor.this)); mApkGenerationDialog = new MaterialDialog.Builder(TemplateEditor.this) @@ -471,7 +485,7 @@ public void onFail(Exception e) { keyPassword = getString(R.string.key_password); aliasName = getString(R.string.alias_name); aliaspassword = getString(R.string.alias_password); - keyStoreDetails = new KeyStoreDetails("TestKeyStore.jks", keyPassword, aliasName, aliaspassword); + keyStoreDetails = new KeyStoreDetails(keyPassword, aliasName, aliaspassword); signer = new SignerThread(getApplicationContext(), selectedTemplate.getApkFilePath(), saveProject(), keyStoreDetails, selectedTemplate.getAssetsFilePath(), selectedTemplate.getAssetsFileName(TemplateEditor.this)); mApkGenerationDialog = new MaterialDialog.Builder(TemplateEditor.this) @@ -600,8 +614,10 @@ private String saveProject() { EditText authorEditText = (EditText) findViewById(R.id.author_name); EditText titleEditText = (EditText) findViewById(R.id.template_title); assert findViewById(R.id.author_name) != null; + assert ((EditText) findViewById(R.id.author_name)) != null; String author = ((EditText) findViewById(R.id.author_name)).getText().toString(); assert findViewById(R.id.template_title) != null; + assert ((EditText) findViewById(R.id.template_title)) != null; String title = ((EditText) findViewById(R.id.template_title)).getText().toString(); if ("".equals(author)) { assert authorEditText != null; @@ -637,7 +653,7 @@ private String saveProject() { doc.appendChild(rootElement); Element dataElement = doc.createElement("data"); rootElement.appendChild(dataElement); - if (selectedTemplate.getItems(doc).size() == 0 || (selectedTemplate.getItems(doc).size() < 2 && templateId == 5)) { + if (selectedTemplate.getItems(doc).size() == 0 || (selectedTemplate.getItems(doc).size() < 2 && (templateId == 5 || templateId == 7))) { Toast.makeText(this, "Unable to perform action: No Data", Toast.LENGTH_SHORT).show(); return null; } @@ -679,9 +695,11 @@ public void onBackPressed() { * @return Absolute path of the saved file. Null if there is some error. * @brief Saves the current project into a .buildmlearn file. */ - protected String saveDraft() { + private String saveDraft() { + assert ((EditText) findViewById(R.id.author_name)) != null; String author = ((EditText) findViewById(R.id.author_name)).getText().toString(); + assert ((EditText) findViewById(R.id.template_title)) != null; String title = ((EditText) findViewById(R.id.template_title)).getText().toString(); @@ -808,8 +826,9 @@ private void parseSavedFile(String path) { Object templateObject = templateClass.newInstance(); selectedTemplate = (TemplateInterface) templateObject; + selectedTemplate.setTemplateId(templateId); populateListView(selectedTemplate.loadProjectTemplateEditor(this, items)); - if (templateId == 5) { + if (templateId == 5 || templateId == 7) { populateMetaView(selectedTemplate.loadProjectMetaEditor(this, doc)); } File draftDir = new File(toolkit.getDraftDir()); 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 681ef389..a11fe203 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 @@ -28,10 +28,12 @@ protected void onCreate(Bundle savedInstanceState) { ViewPager mPager = (ViewPager) findViewById(R.id.pager); // mPager.setAdapter(mAdapter); + assert mPager != null; mPager.setAdapter(mAdapter); CirclePageIndicator mIndicator = (CirclePageIndicator) findViewById(R.id.indicator); + assert mIndicator != null; mIndicator.setViewPager(mPager); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/DraftProjectAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/DraftProjectAdapter.java index 0852d6a7..053851ea 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/DraftProjectAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/DraftProjectAdapter.java @@ -11,14 +11,19 @@ import org.buildmlearn.toolkit.views.TextViewPlus; import java.util.ArrayList; +import java.util.Locale; /** * Created by scopeinfinity on 10/3/16. */ + +/** + * @brief Adapter used for DraftsFragment to show the items + */ public class DraftProjectAdapter extends BaseAdapter { - private Context mContext; - private ArrayList data; + private final Context mContext; + private final ArrayList data; public DraftProjectAdapter(Context mContext, ArrayList data) { this.mContext = mContext; @@ -68,8 +73,8 @@ public View getView(int position, View convertView, ViewGroup parent) { } SavedProject projectData = getItem(position); - holder.draftSubtitle.setText("Last Modified: " + projectData.getTime() ); - holder.draftTitle.setText("Drafted on "+projectData.getDate()); + holder.draftSubtitle.setText(String.format(Locale.ENGLISH, "Last Modified: %s", projectData.getTime())); + holder.draftTitle.setText(String.format(Locale.ENGLISH, "Drafted on %s", projectData.getDate())); holder.draftIcon.setText("D"); convertView.setTag(holder); return convertView; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/SavedApiAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/SavedApiAdapter.java index b3ac6a80..e0e541d8 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/SavedApiAdapter.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/SavedApiAdapter.java @@ -21,8 +21,8 @@ public class SavedApiAdapter extends BaseAdapter { - private Context mContext; - private ArrayList data; + private final Context mContext; + private final ArrayList data; public SavedApiAdapter(Context mContext, ArrayList data) { this.mContext = mContext; @@ -72,7 +72,7 @@ public View getView(int position, View convertView, ViewGroup parent) { } SavedApi apiData = getItem(position); - holder.details.setText("Modified: " + apiData.getDate() + ", Author: " + apiData.getAuthor()); + holder.details.setText(String.format(Locale.ENGLISH, "Modified: %s, Author: ", apiData.getDate(), apiData.getAuthor())); holder.apkName.setText(apiData.getName()); holder.projectIcon.setText(apiData.getName().substring(0, 1).toUpperCase(Locale.US)); convertView.setTag(holder); 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 f718b25b..be14169a 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 @@ -1,19 +1,17 @@ package org.buildmlearn.toolkit.adapter; 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 org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.fragment.LoadProjectFragment; import org.buildmlearn.toolkit.model.SavedProject; import org.buildmlearn.toolkit.views.TextViewPlus; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.Locale; /** @@ -26,7 +24,6 @@ public class SavedProjectAdapter extends BaseAdapter { private final Context mContext; private final ArrayList data; private int selectedPosition; - private int sortType; public SavedProjectAdapter(Context mContext, ArrayList data) { this.mContext = mContext; @@ -58,15 +55,14 @@ public long getItemId(int i) { return i; } + public int getSelectedPosition() { + return selectedPosition; + } public void setSelectedPosition(int selectedPosition) { this.selectedPosition = selectedPosition; } - public int getSelectedPosition() { - return selectedPosition; - } - /** * {@inheritDoc} */ @@ -86,57 +82,19 @@ public View getView(int position, View convertView, ViewGroup parent) { } if (selectedPosition == position) { - convertView.setBackgroundColor(mContext.getResources().getColor(R.color.color_divider)); + convertView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.color_divider)); } else { convertView.setBackgroundColor(0); } SavedProject projectData = getItem(position); - holder.details.setText("Modified: " + projectData.getDate() + ", Author: " + projectData.getAuthor()); + holder.details.setText(String.format(Locale.ENGLISH, "Modified: %s, Author: ", projectData.getDate(), projectData.getAuthor())); holder.projectName.setText(projectData.getName()); holder.projectIcon.setText(projectData.getName().substring(0, 1).toUpperCase(Locale.US)); convertView.setTag(holder); return convertView; } - public void setSortType(int sortType) { - this.sortType = sortType; - } - - public int getSortType() { - return sortType; - } - - public void sort() { - Comparator comparator = null; - switch (sortType) { - case LoadProjectFragment.SORT_TYPE_MODIFIED : - comparator = new Comparator() { - public int compare(SavedProject f1, SavedProject f2) { - //f1 Modified later than f2 - return Long.valueOf(f2.getFile().lastModified()).compareTo(f1.getFile().lastModified()); - } - }; - break; - case LoadProjectFragment.SORT_TYPE_NAME : - comparator = new Comparator() { - public int compare(SavedProject f1, SavedProject f2) { - return f1.getName().compareToIgnoreCase(f2.getName()); - } - }; - break; - case LoadProjectFragment.SORT_TYPE_AUTHOR : - comparator = new Comparator() { - public int compare(SavedProject f1, SavedProject f2) { - return f1.getAuthor().compareToIgnoreCase(f2.getAuthor()); - } - }; - break; - - } - Collections.sort(data, comparator); - } - public class ProjectHolder { public TextViewPlus projectName; public TextViewPlus projectIcon; 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 4b735321..079014ea 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 @@ -1,51 +1,128 @@ package org.buildmlearn.toolkit.adapter; +import android.app.Activity; import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; import android.support.annotation.ColorRes; import android.support.v7.widget.CardView; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.model.Template; +import java.lang.ref.WeakReference; + /** * @brief Adapter used for showing Templates available in the toolkit - * + *

* Created by Abhishek on 23-05-2015. */ -public class TemplateAdapter extends BaseAdapter { +public class TemplateAdapter extends RecyclerView.Adapter { private final Context context; private final Template[] templates = Template.values(); private final ListColor[] colors = ListColor.values(); + private ViewHolder.SetOnClickListener listener; public TemplateAdapter(Context context) { this.context = context; } - /** - * {@inheritDoc} - */ - @Override - public int getCount() { - return templates.length; + public static boolean cancelPotentialWork(int data, ImageView imageView) { + final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final int bitmapData = bitmapWorkerTask.data; + // If bitmapData is not yet set or it differs from the new data + if (bitmapData == 0 || bitmapData != data) { + // Cancel previous task + bitmapWorkerTask.cancel(true); + } else { + // The same work is already in progress + return false; + } + } + // No task associated with the ImageView, or an existing task was cancelled + return true; + } + + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; + } + + public void setOnClickListener(ViewHolder.SetOnClickListener clickListener) { + this.listener = clickListener; } - /** - * {@inheritDoc} - */ @Override - public Template getItem(int i) { + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) { + int layoutResource = 0; + LayoutInflater inflater = ((Activity) context).getLayoutInflater(); + int viewType = getItemViewType(position); + switch (viewType) { + case 0: + layoutResource = R.layout.item_template_right; + break; + case 1: + layoutResource = R.layout.item_template_left; + break; + } + + View view = inflater.inflate(layoutResource, viewGroup, false); + + return new ViewHolder(view); + } + + private Template getItem(int i) { return templates[i]; } + @Override + public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { + + ViewHolder vh = (ViewHolder) viewHolder; + Template template = getItem(position); + + vh.getTitle().setText(template.getTitle()); + vh.getDescription().setText(template.getDescription()); + + int color = colors[position % colors.length].getColor(); + vh.getCardView().setCardBackgroundColor(color); + vh.setItemClickListener(listener); + + if (cancelPotentialWork(template.getImage(), vh.getImage())) { + final BitmapWorkerTask task = new BitmapWorkerTask(context, vh.getImage()); + final AsyncDrawable asyncDrawable = + new AsyncDrawable(context.getResources(), null, task); + vh.getImage().setImageDrawable(asyncDrawable); + task.execute(template.getImage()); + } + } + + @Override + public int getItemCount() { + return templates.length; + } + /** * {@inheritDoc} */ @@ -54,40 +131,20 @@ public long getItemId(int i) { return i; } - /** - * {@inheritDoc} - */ @Override - public View getView(int i, View view, ViewGroup viewGroup) { - - LayoutInflater mInflater; - mInflater = LayoutInflater.from(context); - - if (i % 2 == 0) { - view = mInflater.inflate(R.layout.item_template_right, viewGroup, false); - } else { - view = mInflater.inflate(R.layout.item_template_left, viewGroup, false); - } - - Template template = getItem(i); - - ((TextView) view.findViewById(R.id.title)).setText(template.getTitle()); - ((TextView) view.findViewById(R.id.description)).setText(template.getDescription()); - ((ImageView) view.findViewById(R.id.image)).setImageResource(template.getImage()); - - int color = colors[i % colors.length].getColor(); - ((CardView) view.findViewById(R.id.card_view)).setCardBackgroundColor(color); - - return view; + public int getItemViewType(int position) { + return position % 2; } - private enum ListColor { + enum ListColor { BLUE("#29A6D4"), GREEN("#1C7D6C"), ORANGE("#F77400"), RED("#F53B3C"), GRAYISH("#78909C"), - PURPLE("#AB47BC"); + PURPLE("#AB47BC"), + YELLOW("#F9A01E"), + YELLOW_GREEN("#9ACD32"); private @ColorRes @@ -102,4 +159,148 @@ public int getColor() { return color; } } + + public interface SetOnClickListener extends ViewHolder.SetOnClickListener { + void onItemClick(int position); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + public final TextView title; + public final TextView description; + public final ImageView image; + public final CardView cardView; + SetOnClickListener listener; + + public ViewHolder(final View v) { + super(v); + title = ((TextView) v.findViewById(R.id.title)); + description = ((TextView) v.findViewById(R.id.description)); + image = ((ImageView) v.findViewById(R.id.image)); + cardView = ((CardView) v.findViewById(R.id.card_view)); + + v.setClickable(true); + v.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (listener != null) { + listener.onItemClick(getAdapterPosition()); + } + } + }); + } + + public ImageView getImage() { + return image; + } + + public CardView getCardView() { + return cardView; + } + + public TextView getDescription() { + return description; + } + + public TextView getTitle() { + return title; + } + + public void setItemClickListener(SetOnClickListener itemClickListener) { + this.listener = itemClickListener; + } + + public interface SetOnClickListener { + void onItemClick(int position); + } + } + + static class AsyncDrawable extends BitmapDrawable { + private final WeakReference bitmapWorkerTaskReference; + + public AsyncDrawable(Resources res, Bitmap bitmap, + BitmapWorkerTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = + new WeakReference(bitmapWorkerTask); + } + + public BitmapWorkerTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } + } + + class BitmapWorkerTask extends AsyncTask { + private final WeakReference imageViewReference; + private int data = 0; + private Context mContext; + + public BitmapWorkerTask(Context context, ImageView imageView) { + // Use a WeakReference to ensure the ImageView can be garbage collected + mContext = context; + imageViewReference = new WeakReference(imageView); + } + + // Decode image in background. + @Override + protected Bitmap doInBackground(Integer... params) { + data = params[0]; + return decodeSampledBitmapFromResource(context.getResources(), data, 141, 180); + } + + // Once complete, see if ImageView is still around and set bitmap. + @Override + protected void onPostExecute(Bitmap bitmap) { + if (isCancelled()) { + bitmap = null; + } + + if (imageViewReference != null && bitmap != null) { + final ImageView imageView = imageViewReference.get(); + final BitmapWorkerTask bitmapWorkerTask = + getBitmapWorkerTask(imageView); + if (this == bitmapWorkerTask && imageView != null) { + imageView.setImageBitmap(bitmap); + } + } + } + + public Bitmap decodeSampledBitmapFromResource(Resources res, int resId, + int reqWidth, int reqHeight) { + + // First decode with inJustDecodeBounds=true to check dimensions + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeResource(res, resId, options); + + // Calculate inSampleSize + options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); + + // Decode bitmap with inSampleSize set + options.inJustDecodeBounds = false; + return BitmapFactory.decodeResource(res, resId, options); + } + + public int calculateInSampleSize( + BitmapFactory.Options options, int reqWidth, int reqHeight) { + // Raw height and width of image + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + // Calculate the largest inSampleSize value that is a power of 2 and keeps both + // height and width larger than the requested height and width. + while ((halfHeight / inSampleSize) >= reqHeight + && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + } } 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 e65421a6..553341d1 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 @@ -47,10 +47,6 @@ private Tutorial getItem(int position) { return mTutorials[position]; } - public long getItemId(int position) { - return position; - } - /** * {@inheritDoc} */ 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 index 6b156df5..03f5c5c3 100644 --- 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 @@ -3,6 +3,10 @@ /** * Created by Anupam (opticod) on 5/6/16. */ + +/** + * @brief Constants used in comprehension template's simulator relating databases. + */ public class Constants { public static final String firstrun = "firstRun"; public static final int COL_TITLE = 1; 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 index 9544b5a8..fc4ecec8 100644 --- 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 @@ -6,6 +6,10 @@ * Created by Anupam (opticod) on 5/6/16. */ +/** + * @brief Contains database contracts for comprehension template's simulator. + */ + class ComprehensionContract { public static final class Questions implements BaseColumns { 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 index 3817db31..53f65220 100644 --- 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 @@ -11,6 +11,10 @@ * Created by Anupam (opticod) on 5/6/16. */ +/** + * @brief DatabaseHelper for comprehension template's simulator. + */ + class ComprehensionDBHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "comprehension.db"; 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 index c990d908..79aac38f 100644 --- 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 @@ -16,6 +16,10 @@ /** * Created by Anupam (opticod) on 5/6/16. */ + +/** + * @brief Contains database util functions for comprehension template's simulator. + */ public class ComprehensionDb { private static final String EQUAL = " == "; @@ -30,10 +34,6 @@ public void open() throws SQLException { db = dbHelper.getWritableDatabase(); } - public boolean isOpen() { - return db.isOpen(); - } - public void close() { dbHelper.close(); } 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 index e83a9702..5d6ce10e 100644 --- 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 @@ -1,7 +1,5 @@ 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; @@ -16,9 +14,13 @@ /** * Created by Anupam (opticod) on 5/6/16. */ + +/** + * @brief Contains xml data utils for comprehension template's simulator. + */ public class DataUtils { - public static String[] readTitleAuthor(Context myContext) { + public static String[] readTitleAuthor() { String result[] = new String[2]; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 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 index d0063b50..8b58052a 100644 --- 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 @@ -28,6 +28,10 @@ /** * Created by Anupam (opticod) on 5/6/16. */ + +/** + * @brief Used to parse XML and save in database for comprehension template's simulator. + */ public class FetchXMLTask extends AsyncTask { private final Context mContext; 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 index 6987b871..fc564358 100644 --- 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 @@ -23,6 +23,10 @@ /** * Created by Anupam (opticod) on 5/6/16. */ + +/** + * @brief Last Fragment for comprehension template's simulator. + */ public class LastFragment extends Fragment { public static Fragment newInstance() { @@ -63,6 +67,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { welcomeAlert.show(); assert welcomeAlert.findViewById(android.R.id.message) != null; assert welcomeAlert.findViewById(android.R.id.message) != null; + assert ((TextView) welcomeAlert.findViewById(android.R.id.message)) != null; ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); break; default: //do nothing 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 index 16821273..1e2ada4a 100644 --- 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 @@ -31,6 +31,11 @@ /** * Created by Anupam (opticod) on 5/6/16. */ + +/** + * @brief Main Fragment for comprehension template's simulator. + */ + public class MainFragment extends Fragment implements NavigationView.OnNavigationItemSelectedListener { private View rootView; @@ -63,6 +68,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { welcomeAlert.show(); assert welcomeAlert.findViewById(android.R.id.message) != null; assert welcomeAlert.findViewById(android.R.id.message) != null; + assert ((TextView) welcomeAlert.findViewById(android.R.id.message)) != null; ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); break; default: //do nothing 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 index f0eeee6e..da34a9e9 100644 --- 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 @@ -30,6 +30,10 @@ /** * Created by Anupam (opticod) on 5/6/16. */ + +/** + * @brief Question Fragment for comprehension template's simulator. + */ public class QuestionFragment extends Fragment implements NavigationView.OnNavigationItemSelectedListener { @@ -64,6 +68,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { welcomeAlert.show(); assert welcomeAlert.findViewById(android.R.id.message) != null; assert welcomeAlert.findViewById(android.R.id.message) != null; + assert ((TextView) welcomeAlert.findViewById(android.R.id.message)) != null; ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); break; default: //do nothing 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 index 1b370bbd..df114b21 100644 --- 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 @@ -19,6 +19,10 @@ /** * Created by Anupam (opticod) on 5/6/16. */ + +/** + * @brief Splash intro Fragment for comprehension template's simulator. + */ public class SplashFragment extends Fragment { public static Fragment newInstance(String path) { @@ -33,7 +37,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, View rootView = inflater.inflate(R.layout.fragment_splash, container, false); final Activity mActivity = getActivity(); - final String result[] = DataUtils.readTitleAuthor(getContext()); + final String result[] = DataUtils.readTitleAuthor(); TextView title = (TextView) rootView.findViewById(R.id.title); TextView author_name = (TextView) rootView.findViewById(R.id.author_name); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/Constants.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/Constants.java new file mode 100644 index 00000000..ed14853e --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/Constants.java @@ -0,0 +1,24 @@ +package org.buildmlearn.toolkit.dictationtemplate; + +import org.buildmlearn.toolkit.dictationtemplate.data.DictContract; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief Constants used in dictation template's simulator relating databases. + */ +public class Constants { + public static final String[] DICT_COLUMNS = { + DictContract.Dict.TABLE_NAME + "." + DictContract.Dict._ID, + DictContract.Dict.TITLE, + DictContract.Dict.PASSAGE + }; + public static final int COL_ID = 0; + public static final int COL_TITLE = 1; + public static final int COL_PASSAGE = 2; + public static final String firstrun = "firstRun"; + public static final String passage = "PASSAGE"; + public static String XMLFileName = "dictation_content.xml"; +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/adapter/DictArrayAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/adapter/DictArrayAdapter.java new file mode 100644 index 00000000..da1424e7 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/adapter/DictArrayAdapter.java @@ -0,0 +1,58 @@ +package org.buildmlearn.toolkit.dictationtemplate.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.dictationtemplate.Constants; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief Custom Adapter for dictation template's simulator. + */ +public class DictArrayAdapter extends CursorAdapter { + + public DictArrayAdapter(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_dict, 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/dictationtemplate/data/DataUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DataUtils.java new file mode 100644 index 00000000..45a9ddeb --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DataUtils.java @@ -0,0 +1,48 @@ +package org.buildmlearn.toolkit.dictationtemplate.data; + +import org.buildmlearn.toolkit.dictationtemplate.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 10/7/16. + */ + +/** + * @brief Contains xml data utils for dictation template's simulator. + */ +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/dictationtemplate/data/DictContract.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictContract.java new file mode 100644 index 00000000..99655b0e --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictContract.java @@ -0,0 +1,23 @@ +package org.buildmlearn.toolkit.dictationtemplate.data; + +import android.provider.BaseColumns; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief Contains database contracts for dictation template's simulator. + */ + +public class DictContract { + + public static final class Dict implements BaseColumns { + + public static final String TABLE_NAME = "dictation"; + + public static final String TITLE = "title"; + public static final String PASSAGE = "passage"; + + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictDBHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictDBHelper.java new file mode 100644 index 00000000..7e6f52d2 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictDBHelper.java @@ -0,0 +1,41 @@ +package org.buildmlearn.toolkit.dictationtemplate.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.buildmlearn.toolkit.dictationtemplate.data.DictContract.Dict; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief DatabaseHelper for dictation template's simulator. + */ + +class DictDBHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "dictation.db"; + private static final int DATABASE_VERSION = 1; + + public DictDBHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + final String SQL_CREATE__TABLE = "CREATE TABLE " + Dict.TABLE_NAME + " (" + + Dict._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Dict.TITLE + " TEXT," + + Dict.PASSAGE + " TEXT)"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE); + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Dict.TABLE_NAME); + onCreate(sqLiteDatabase); + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictDb.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictDb.java new file mode 100644 index 00000000..36b7303b --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictDb.java @@ -0,0 +1,93 @@ +package org.buildmlearn.toolkit.dictationtemplate.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 10/7/16. + */ + +/** + * @brief Contains database util functions for dictation template's simulator. + */ +public class DictDb { + + private static final String EQUAL = " == "; + private final DictDBHelper dbHelper; + private SQLiteDatabase db; + + public DictDb(Context context) { + dbHelper = new DictDBHelper(context); + } + + public void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public void close() { + dbHelper.close(); + } + + public Cursor getDictsCursor() { + + return db.query( + DictContract.Dict.TABLE_NAME, + null, + null, + null, + null, + null, + null + ); + } + + public Cursor getDictCursorById(int id) { + + String selection = DictContract.Dict._ID + EQUAL + id; + + return db.query( + DictContract.Dict.TABLE_NAME, + null, + selection, + null, + null, + null, + null + ); + } + + public long getCount() { + + return DatabaseUtils.queryNumEntries(db, + DictContract.Dict.TABLE_NAME); + } + + public void deleteAll() { + db.delete(DictContract.Dict.TABLE_NAME, null, null); + db.execSQL("delete from sqlite_sequence where name='" + DictContract.Dict.TABLE_NAME + "';"); + } + + public int bulkInsert(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(DictContract.Dict.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/dictationtemplate/data/DictModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictModel.java new file mode 100644 index 00000000..02f13676 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/DictModel.java @@ -0,0 +1,63 @@ +package org.buildmlearn.toolkit.dictationtemplate.data; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief Model used to save dict entries in database for comprehension template's simulator. + */ +public class DictModel implements Parcelable { + public final static Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public DictModel createFromParcel(Parcel parcel) { + return new DictModel(parcel); + } + + @Override + public DictModel[] newArray(int size) { + return new DictModel[size]; + } + }; + private String title; + private String passage; + + public DictModel() { + } + + private DictModel(Parcel in) { + this.title = in.readString(); + this.passage = in.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(title); + dest.writeString(passage); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPassage() { + return passage; + } + + public void setPassage(String passage) { + this.passage = passage; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/FetchXMLTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/FetchXMLTask.java new file mode 100644 index 00000000..0dcdd64e --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/data/FetchXMLTask.java @@ -0,0 +1,137 @@ +package org.buildmlearn.toolkit.dictationtemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.os.AsyncTask; + +import org.buildmlearn.toolkit.dictationtemplate.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 10/7/16. + */ + +/** + * @brief Used to parse XML and save in database for dictation template's simulator. + */ + +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 Dicts) { + + Vector cVVector = new Vector<>(Dicts.size()); + + for (int i = 0; i < Dicts.size(); i++) { + + String title; + String passage; + + DictModel dictInfo = Dicts.get(i); + + title = dictInfo.getTitle(); + passage = dictInfo.getPassage(); + + ContentValues DictValues = new ContentValues(); + + DictValues.put(DictContract.Dict.TITLE, title); + DictValues.put(DictContract.Dict.PASSAGE, passage); + + cVVector.add(DictValues); + } + // add to database + if (cVVector.size() > 0) { + ContentValues[] cvArray = new ContentValues[cVVector.size()]; + cVVector.toArray(cvArray); + DictDb db = new DictDb(mContext); + db.open(); + db.bulkInsert(cvArray); + db.close(); + } + } + + @Override + protected Void doInBackground(String... params) { + + if (params.length == 0) { + return null; + } + String fileName = params[0]; + ArrayList mList; + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setValidating(false); + + DocumentBuilder db; + Document doc; + try { + mList = new ArrayList<>(); + File fXmlFile = new File(Constants.XMLFileName); + db = dbf.newDocumentBuilder(); + doc = db.parse(fXmlFile); + doc.normalize(); + + NodeList childNodes = doc.getElementsByTagName("item"); + + for (int i = 0; i < childNodes.getLength(); i++) { + DictModel app = new DictModel(); + + Node child = childNodes.item(i); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element2 = (Element) child; + + app.setTitle(getValue("dictation_title", element2)); + app.setPassage(getValue("dictation_passage", 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/dictationtemplate/fragment/DetailActivityFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/DetailActivityFragment.java new file mode 100644 index 00000000..4d0f870f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/DetailActivityFragment.java @@ -0,0 +1,263 @@ +package org.buildmlearn.toolkit.dictationtemplate.fragment; + +import android.app.FragmentManager; +import android.app.ProgressDialog; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.os.Build; +import android.os.Bundle; +import android.speech.tts.TextToSpeech; +import android.speech.tts.UtteranceProgressListener; +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.view.WindowManager; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.dictationtemplate.Constants; +import org.buildmlearn.toolkit.dictationtemplate.data.DataUtils; +import org.buildmlearn.toolkit.dictationtemplate.data.DictDb; + +import java.util.HashMap; +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief Fragment for taking user input(dictation) in dictation template's simulator. + */ +public class DetailActivityFragment extends Fragment implements LoaderCallbacks { + + private static final int DETAIL_LOADER = 0; + + private View rootView; + private String dict_Id; + private DictDb db; + private TextToSpeech tts; + private ProgressDialog progress; + + 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) { + dict_Id = arguments.getString(Intent.EXTRA_TEXT); + } + rootView = inflater.inflate(R.layout.fragment_detail_dict, container, false); + + db = new DictDb(getContext()); + db.open(); + + getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + + 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.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.dictationtemplate.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; + 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; + } + }); + + 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 != dict_Id) { + switch (id) { + case DETAIL_LOADER: + + return new CursorLoader(getActivity(), null, Constants.DICT_COLUMNS, null, null, null) { + @Override + public Cursor loadInBackground() { + return db.getDictCursorById(Integer.parseInt(dict_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: + + final EditText passageText = (EditText) rootView.findViewById(R.id.enter_passage); + final String passage = data.getString(Constants.COL_PASSAGE); + + rootView.findViewById(R.id.ico_speak).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + progress = new ProgressDialog(getActivity()); + progress.setCancelable(false); + progress.setMessage("Loading TTS Engine..."); + progress.show(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + String utteranceId = passage.hashCode() + ""; + tts.speak(passage, TextToSpeech.QUEUE_FLUSH, null, utteranceId); + } else { + HashMap map = new HashMap<>(); + map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "dict"); + tts.speak(passage, TextToSpeech.QUEUE_FLUSH, map); + } + } + }); + + rootView.findViewById(R.id.submit).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String passage_usr = passageText.getText().toString(); + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(dict_Id)); + arguments.putString(Constants.passage, passage_usr); + + Fragment frag = ResultActivityFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + } + }); + + rootView.findViewById(R.id.back).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(), org.buildmlearn.toolkit.dictationtemplate.fragment.MainActivityFragment.newInstance()).addToBackStack(null).commit(); + } + }); + + break; + default: + throw new UnsupportedOperationException("Unknown Loader"); + } + } + + @Override + public void onLoaderReset(Loader loader) { + // This constructor is intentionally empty + } + + @Override + public void onDestroyView() { + db.close(); + super.onDestroyView(); + } + + @Override + public void onPause() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + tts = new TextToSpeech(getContext(), new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int result = tts.setLanguage(Locale.US); + if (result == TextToSpeech.LANG_MISSING_DATA + || result == TextToSpeech.LANG_NOT_SUPPORTED) { + Toast.makeText(getContext(), "US English is not supported. Playing in device's default installed language.", Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(getContext(), "Initialization Failed!", Toast.LENGTH_SHORT).show(); + } + } + }); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { + tts.setOnUtteranceProgressListener(new UtteranceProgressListener() { + @Override + public void onStart(String utteranceId) { + progress.dismiss(); + } + + @Override + public void onDone(String utteranceId) { + + } + + @Override + public void onError(String utteranceId) { + + } + }); + } + + SharedPreferences prefs = getActivity().getSharedPreferences("Radio", getContext().MODE_PRIVATE); + float rate = prefs.getInt("radio_b", 1); + if (rate == 0) { + rate = 0.5F; + } + tts.setSpeechRate(rate); + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/MainActivityFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/MainActivityFragment.java new file mode 100644 index 00000000..15526beb --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/MainActivityFragment.java @@ -0,0 +1,226 @@ +package org.buildmlearn.toolkit.dictationtemplate.fragment; + +import android.content.Intent; +import android.content.SharedPreferences; +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.RadioGroup; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.dictationtemplate.Constants; +import org.buildmlearn.toolkit.dictationtemplate.adapter.DictArrayAdapter; +import org.buildmlearn.toolkit.dictationtemplate.data.DataUtils; +import org.buildmlearn.toolkit.dictationtemplate.data.DictContract; +import org.buildmlearn.toolkit.dictationtemplate.data.DictDb; +import org.buildmlearn.toolkit.dictationtemplate.data.DictModel; + +import java.util.ArrayList; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief Fragment to hear dictation in dictation template's simulator. + */ +public class MainActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks { + + private static final String SELECTED_KEY = "selected_position"; + private static final int DICT_LOADER = 0; + + private DictArrayAdapter dictListAdapter; + private int mPosition = ListView.INVALID_POSITION; + private ListView listView; + private ArrayList dictList; + private View rootView; + private DictDb db; + + public static Fragment newInstance() { + return new MainActivityFragment(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putParcelableArrayList("dictList", dictList); + 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("dictList")) { + dictList = new ArrayList<>(); + } else { + dictList = savedInstanceState.getParcelableArrayList("dictList"); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + dictListAdapter = + new DictArrayAdapter( + getActivity()); + + rootView = inflater.inflate(R.layout.fragment_main_dict, container, false); + + Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.card_toolbar); + toolbar.setTitle("List of Passages :"); + + 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_dict))); + builder.setMessage(getResources().getText(R.string.about_text_dict)); + builder.setPositiveButton("OK", null); + AlertDialog welcomeAlert = builder.create(); + welcomeAlert.show(); + assert welcomeAlert.findViewById(android.R.id.message) != null; + 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_dict); + listView.setAdapter(dictListAdapter); + + 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.dictationtemplate.fragment.DetailActivityFragment.newInstance(); + frag.setArguments(arguments); + getActivity().getSupportFragmentManager().beginTransaction().replace(((ViewGroup) getView().getParent()).getId(), frag).addToBackStack(null).commit(); + + mPosition = position; + } + }); + + db = new DictDb(getContext()); + db.open(); + + if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY)) { + mPosition = savedInstanceState.getInt(SELECTED_KEY); + } + + SharedPreferences prefs = getActivity().getSharedPreferences("Radio", getContext().MODE_PRIVATE); + int pos = prefs.getInt("radio_b", 1); + RadioGroup rg = (RadioGroup) rootView.findViewById(R.id.radio_group); + rg.check(rg.getChildAt(pos).getId()); + + return rootView; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + getLoaderManager().initLoader(DICT_LOADER, null, this); + super.onActivityCreated(savedInstanceState); + } + + @Override + public Loader onCreateLoader(int i, Bundle bundle) { + + String sortOrder = DictContract.Dict._ID + " ASC"; + + return new CursorLoader(getActivity(), null, Constants.DICT_COLUMNS, null, null, sortOrder) { + @Override + public Cursor loadInBackground() { + return db.getDictsCursor(); + } + }; + } + + @Override + public void onLoadFinished(Loader cursorLoader, Cursor cursor) { + dictListAdapter.swapCursor(cursor); + + rootView.findViewById(R.id.radioButton1).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SharedPreferences.Editor editor = getActivity().getSharedPreferences("Radio", getContext().MODE_PRIVATE).edit(); + editor.putInt("radio_b", 0); + editor.apply(); + } + }); + + rootView.findViewById(R.id.radioButton2).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SharedPreferences.Editor editor = getActivity().getSharedPreferences("Radio", getContext().MODE_PRIVATE).edit(); + editor.putInt("radio_b", 1); + editor.apply(); + } + }); + + rootView.findViewById(R.id.radioButton3).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SharedPreferences.Editor editor = getActivity().getSharedPreferences("Radio", getContext().MODE_PRIVATE).edit(); + editor.putInt("radio_b", 2); + editor.apply(); + } + }); + + if (mPosition != ListView.INVALID_POSITION) { + listView.smoothScrollToPosition(mPosition); + } + try { + TextView info = (TextView) rootView.findViewById(R.id.empty); + if (dictListAdapter.getCount() == 0) { + info.setText(R.string.list_empty_dict); + info.setVisibility(View.VISIBLE); + } else { + info.setVisibility(View.GONE); + } + } catch (Exception ignored) { + } + } + + @Override + public void onLoaderReset(Loader cursorLoader) { + dictListAdapter.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/dictationtemplate/fragment/ResultActivityFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/ResultActivityFragment.java new file mode 100644 index 00000000..9245311d --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/ResultActivityFragment.java @@ -0,0 +1,201 @@ +package org.buildmlearn.toolkit.dictationtemplate.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.Html; +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.dictationtemplate.Constants; +import org.buildmlearn.toolkit.dictationtemplate.data.DataUtils; +import org.buildmlearn.toolkit.dictationtemplate.data.DictContract; +import org.buildmlearn.toolkit.dictationtemplate.data.DictDb; +import org.buildmlearn.toolkit.utilities.diff_match_patch; + +import java.util.LinkedList; +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief Fragment for displaying score to user in dictation template's simulator. + */ +public class ResultActivityFragment extends Fragment implements LoaderCallbacks { + + private static final int DETAIL_LOADER = 0; + private final ContentValues dictValues; + + private View rootView; + private String dict_Id; + private String passageEntered; + private DictDb db; + + public ResultActivityFragment() { + setHasOptionsMenu(true); + dictValues = new ContentValues(); + } + + public static Fragment newInstance() { + return new ResultActivityFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + Bundle arguments = getArguments(); + if (arguments != null) { + dict_Id = arguments.getString(Intent.EXTRA_TEXT); + passageEntered = arguments.getString(Constants.passage); + } + rootView = inflater.inflate(R.layout.fragment_result_dict, container, false); + + db = new DictDb(getContext()); + db.open(); + + 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.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.dictationtemplate.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; + 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; + } + }); + + 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 != dict_Id) { + switch (id) { + case DETAIL_LOADER: + + return new CursorLoader(getActivity(), null, Constants.DICT_COLUMNS, null, null, null) { + @Override + public Cursor loadInBackground() { + return db.getDictCursorById(Integer.parseInt(dict_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 passage = data.getString(Constants.COL_PASSAGE); + passageEntered += " "; + passage += " "; + + diff_match_patch obj = new diff_match_patch(); + LinkedList llDiffs = obj.diff_WordMode(passageEntered, passage); + String result[] = obj.diff_prettyHtml(llDiffs); + + int numTWords = passage.split(" ").length; + ((TextView) rootView.findViewById(R.id.score)).setText(String.format(Locale.ENGLISH, "SCORE : %s / %d", result[1], numTWords)); + + ((TextView) rootView.findViewById(R.id.checked_text)).setText(Html.fromHtml(result[0])); + + rootView.findViewById(R.id.restart).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, dict_Id); + + Fragment frag = org.buildmlearn.toolkit.dictationtemplate.fragment.DetailActivityFragment.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(); + } + }); + + if (dictValues.size() == 0) { + dictValues.put(DictContract.Dict._ID, data.getString(Constants.COL_ID)); + dictValues.put(DictContract.Dict.TITLE, data.getString(Constants.COL_TITLE)); + dictValues.put(DictContract.Dict.PASSAGE, data.getString(Constants.COL_PASSAGE)); + } + 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/dictationtemplate/fragment/SplashFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/SplashFragment.java new file mode 100644 index 00000000..fa7e53ed --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/dictationtemplate/fragment/SplashFragment.java @@ -0,0 +1,68 @@ +package org.buildmlearn.toolkit.dictationtemplate.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.dictationtemplate.Constants; +import org.buildmlearn.toolkit.dictationtemplate.data.DataUtils; +import org.buildmlearn.toolkit.dictationtemplate.data.DictDb; +import org.buildmlearn.toolkit.dictationtemplate.data.FetchXMLTask; +import org.buildmlearn.toolkit.views.TextViewPlus; + +/** + * Created by Anupam (opticod) on 10/7/16. + */ + +/** + * @brief Splash intro Fragment for dictation template's simulator. + */ +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.dictation_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(), MainActivityFragment.newInstance()).addToBackStack(null).commit(); + } + }); + + DictDb db = new DictDb(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/flashcardtemplate/Constants.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/Constants.java new file mode 100644 index 00000000..88257075 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/Constants.java @@ -0,0 +1,18 @@ +package org.buildmlearn.toolkit.flashcardtemplate; + +/** + * Created by Anupam (opticod) on 10/8/16. + */ + +/** + * @brief Constants used in flash card template's simulator relating databases. + */ +public class Constants { + public static final String firstrun = "firstRun"; + public static final int COL_QUESTION = 1; + public static final int COL_ANSWER = 2; + public static final int COL_HINT = 3; + public static final int COL_BASE64 = 4; + public static String XMLFileName = "flash_content.xml"; + +} 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 deleted file mode 100644 index 234fd883..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/FlashModel.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.buildmlearn.toolkit.flashcardtemplate; - - -/** - * @brief Simulator code for Flash Card Template - */ -class FlashModel { - private String question; - private String answer; - private String hint; - private String base64; - - - public String getQuestion() { - return question; - } - - public void setQuestion(String question) { - this.question = question; - } - - public String getAnswer() { - return answer; - } - - public void setAnswer(String answer) { - this.answer = answer; - } - - public String getHint() { - return hint; - } - - public void setHint(String hint) { - this.hint = hint; - } - - public String getBase64() { - return base64; - } - - public void setBase64(String base64) { - this.base64 = base64; - } -} 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 deleted file mode 100644 index 58803a02..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/GlobalData.java +++ /dev/null @@ -1,235 +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.flashcardtemplate; - -import android.content.Context; -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 org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -/** - * @brief Simulator code for Flash Card Template - */ -public class GlobalData { - private static GlobalData instance = null; - private final List iQuizList = new ArrayList<>(); - String iQuizTitle = null; - String iQuizAuthor = null; - int totalCards = 0; - ArrayList model = null; - int iSelectedIndex = -1; - private BufferedReader br; - - private 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 = nodeList.item(0); - - return node.getNodeValue(); - } - } - - public void ReadContent(Context myContext) { - try { - br = new BufferedReader(new InputStreamReader(myContext.getAssets() - .open("flashcard_content.txt"))); // throwing a - // FileNotFoundException? - iQuizTitle = br.readLine(); - iQuizAuthor = br.readLine(); - String text; - while ((text = br.readLine()) != null) { - iQuizList.add(text); - } - totalCards = iQuizList.size(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - br.close(); // stop reading - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - - public void readXmlContent(Context myContext, String fileName) { - XmlPullParserFactory factory; - XmlPullParser parser; - InputStreamReader is; - try { - factory = XmlPullParserFactory.newInstance(); - // .setNamespaceAware(true); - factory.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); - - parser = factory.newPullParser(); - - is = new InputStreamReader(myContext.getAssets().open(fileName)); - - parser.setInput(is); - int eventType = parser.getEventType(); - FlashModel app = null; - - while (eventType != XmlPullParser.END_DOCUMENT) { - String name; - switch (eventType) { - case XmlPullParser.START_DOCUMENT: - model = new ArrayList<>(); - break; - case XmlPullParser.START_TAG: - name = parser.getName(); - - if (name.equalsIgnoreCase("title")) { - iQuizTitle = parser.nextText(); - } else if (name.equalsIgnoreCase("author")) { - iQuizAuthor = parser.nextText(); - } else if (name.equalsIgnoreCase("item")) { - app = new FlashModel(); - } else if (app != null) { - if (name.equalsIgnoreCase("question")) { - app.setQuestion(parser.nextText()); - } else if (name.equalsIgnoreCase("answer")) { - app.setAnswer(parser.nextText()); - } else if (name.equalsIgnoreCase("hint")) { - app.setHint(parser.nextText()); - } else if (name.equalsIgnoreCase("image")) { - app.setBase64(parser.nextText()); - } - } - break; - case XmlPullParser.END_TAG: - name = parser.getName(); - if (name.equalsIgnoreCase("item") && app != null) { - model.add(app); - totalCards = model.size(); - } - } - eventType = parser.next(); - - } - } catch (XmlPullParserException | IOException e1) { - e1.printStackTrace(); - } - - } - - public void readXml(String filePath) { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - - dbf.setValidating(false); - - DocumentBuilder db; - Document doc; - - - try { - model = new ArrayList<>(); - File fXmlFile = new File(filePath); - db = dbf.newDocumentBuilder(); - doc = db.parse(fXmlFile); - doc.normalize(); - /* - * NodeList app_nodes = doc - * .getElementsByTagName("buildmlearn_application"); - */ - // NamedNodeMap node = app_nodes.item(0).getAttributes(); - iQuizTitle = doc.getElementsByTagName("title").item(0) - .getChildNodes().item(0).getNodeValue(); - // NodeList author_nodes = doc.getElementsByTagName("author"); - // 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()); - for (int i = 0; i < childNodes.getLength(); i++) { - FlashModel app = new FlashModel(); - - Node child = childNodes.item(i); - - if (child.getNodeType() == Node.ELEMENT_NODE) { - Element element2 = (Element) child; - - app.setQuestion(getValue("question", element2)); - app.setAnswer(getValue("answer", element2)); - app.setHint(getValue("hint", element2)); - app.setBase64(getValue("image", element2)); - - } - model.add(app); - - } - totalCards = model.size(); - - Log.d("tag", "totalCards" + totalCards); - } catch (ParserConfigurationException | IOException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } catch (SAXException 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/flashcardtemplate/MainFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/MainFragment.java deleted file mode 100644 index f19d5ad8..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/MainFragment.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.buildmlearn.toolkit.flashcardtemplate; - -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; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.animation.Animation; -import android.view.animation.Animation.AnimationListener; -import android.view.animation.AnimationUtils; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; - - -/** - * @brief Simulator code for Flash Card Template - */ -public class MainFragment extends Fragment implements - AnimationListener { - 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; - private View view; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - view = inflater.inflate(R.layout.flash_simu_main, container, false); - - animation1 = AnimationUtils.loadAnimation(getActivity(), R.anim.to_middle); - animation1.setAnimationListener(this); - animation2 = AnimationUtils.loadAnimation(getActivity(), R.anim.from_middle); - animation2.setAnimationListener(this); - - questionView = view.findViewById(R.id.questionInMain); - answerView = view.findViewById(R.id.answerInMain); - - questionView.setVisibility(View.VISIBLE); - answerView.setVisibility(View.GONE); - iQuestionIndex = 0; - - questionImage = (ImageView) view.findViewById(R.id.questionImage); - questionText = (TextView) view.findViewById(R.id.flashCardText); - hintText = (TextView) view.findViewById(R.id.questionhint); - flashcardNumber = (TextView) view.findViewById(R.id.flashCardNumber); - - Button flipButton = (Button) view.findViewById(R.id.flip_button); - preButton = (Button) view.findViewById(R.id.pre_button); - Button nextButton = (Button) view.findViewById(R.id.next_button); - - populateQuestion(iQuestionIndex); - currentView = questionView; - - flipButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - - currentView.clearAnimation(); - currentView.setAnimation(animation1); - currentView.startAnimation(animation1); - - } - }); - - preButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (iQuestionIndex != 0) { - isFlipped = false; - - iQuestionIndex--; - questionView.setVisibility(View.VISIBLE); - answerView.setVisibility(View.GONE); - currentView = questionView; - - populateQuestion(iQuestionIndex); - } - - } - }); - - nextButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - - if (iQuestionIndex < gd.model.size() - 1) { - isFlipped = false; - iQuestionIndex++; - questionView.setVisibility(View.VISIBLE); - answerView.setVisibility(View.GONE); - currentView = questionView; - populateQuestion(iQuestionIndex); - - } else { - - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new ScoreFragment()).addToBackStack(null).commit(); - - reInitialize(); - } - - } - }); - return view; - } - - - private void populateQuestion(int index) { - if (index == 0) { - preButton.setEnabled(false); - - } else - preButton.setEnabled(true); - - int cardNum = index + 1; - flashcardNumber.setText("Card #" + cardNum + " of " + gd.totalCards); - FlashModel mFlash = gd.model.get(index); - TextView answerText = (TextView) view.findViewById(R.id.answerText); - if (mFlash.getQuestion() != null) - questionText.setText(mFlash.getQuestion()); - if (mFlash.getHint() != null) - hintText.setText(mFlash.getHint()); - if (mFlash.getAnswer() != null) { - flashCardanswer = mFlash.getAnswer(); - answerText.setText(mFlash.getAnswer()); - } - if (mFlash.getBase64() != null) { - byte[] decodedString = Base64.decode(mFlash.getBase64(), - Base64.DEFAULT); - Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, - 0, decodedString.length); - questionImage.setImageBitmap(decodedByte); - } else { - questionText.setGravity(Gravity.CENTER_VERTICAL); - } - - } - - private void reInitialize() { - iQuestionIndex = 0; - gd.model.clear(); - } - - @Override - public void onAnimationEnd(Animation animation) { - if (animation == animation1) { - - TextView answerText = (TextView) view.findViewById(R.id.answerText); - - if (!isFlipped) { - - answerView.setVisibility(View.VISIBLE); - questionView.setVisibility(View.GONE); - isFlipped = true; - answerText.setText(flashCardanswer); - currentView = answerView; - } else { - - isFlipped = false; - answerText.setText(""); - questionView.setVisibility(View.VISIBLE); - answerView.setVisibility(View.GONE); - currentView = questionView; - } - currentView.clearAnimation(); - currentView.setAnimation(animation2); - currentView.startAnimation(animation2); - - } - - } - - @Override - public void onAnimationRepeat(Animation animation) { - // TODO Auto-generated method stub - - } - - @Override - public void onAnimationStart(Animation animation) { - // TODO Auto-generated method stub - - } - - -} 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 deleted file mode 100644 index 63d59821..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/ScoreFragment.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.buildmlearn.toolkit.flashcardtemplate; - -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; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.constant.Constants; - - -/** - * @brief Simulator code for Flash Card Template - */ -public class ScoreFragment extends Fragment { - - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - View view = inflater.inflate(R.layout.flash_simu_finish, container, false); - GlobalData gd = GlobalData.getInstance(); - TextView mCardQuizName = (TextView) view.findViewById(R.id.tv_lastcard); - mCardQuizName.setText(gd.iQuizTitle); - - Button startAgainButton = (Button) view.findViewById(R.id.btn_restart); - startAgainButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, StartFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), StartFragment.TAG).addToBackStack(null).commit(); -//t - } - }); - - Button quitButton = (Button) view.findViewById(R.id.btn_exit); - quitButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - getActivity().finish(); - } - }); - return view; - } - -} 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 deleted file mode 100644 index b8fcfc9a..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/StartFragment.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.buildmlearn.toolkit.flashcardtemplate; - -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; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.constant.Constants; - - -/** - * @brief Simulator code for Flash Card Template - */ -public class StartFragment extends Fragment { - - public static final String TAG = "Start Fragment"; - - public static Fragment newInstance(String path) { - StartFragment fragment = new StartFragment(); - Bundle bundle = new Bundle(); - bundle.putString(Constants.SIMULATOR_FILE_PATH, path); - fragment.setArguments(bundle); - return fragment; - } - - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - View view = inflater.inflate(R.layout.flash_simu_start_view, container, false); - - GlobalData gd = GlobalData.getInstance(); - gd.readXml(getArguments().getString(Constants.SIMULATOR_FILE_PATH)); - - TextView quizAuthor = (TextView) view.findViewById(R.id.tv_author); - TextView quizTitle = (TextView) view.findViewById(R.id.tv_apptitle); - - quizAuthor.setText(gd.iQuizAuthor); - quizTitle.setText(gd.iQuizTitle); - - Button startButton = (Button) view.findViewById(R.id.btn_start); - startButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new MainFragment()).addToBackStack(null).commit(); - - } - }); - - return view; - } - - -} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/animations/FlipPageTransformer.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/animations/FlipPageTransformer.java new file mode 100644 index 00000000..35ce4cfe --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/animations/FlipPageTransformer.java @@ -0,0 +1,48 @@ +package org.buildmlearn.toolkit.flashcardtemplate.animations; + +import android.support.v4.view.ViewPager; +import android.view.View; + +/** + * Created by Ashish Goel on 1/30/2016. + */ +public class FlipPageTransformer implements ViewPager.PageTransformer { + + @Override + public void transformPage(View page, float position) { + float percentage = 1 - Math.abs(position); + setVisibility(page, position); + setTranslation(page); + setSize(page, position, percentage); + setRotation(page, position, percentage); + } + + private void setVisibility(View page, float position) { + if (position < 0.5 && position > -0.5) { + page.setVisibility(View.VISIBLE); + } else { + page.setVisibility(View.INVISIBLE); + } + } + + private void setTranslation(View page) { + ViewPager viewPager = (ViewPager) page.getParent(); + int scroll = viewPager.getScrollX() - page.getLeft(); + page.setTranslationX(scroll); + } + + private void setSize(View page, float position, float percentage) { + if (percentage < 0.8) + percentage = 0.8f; + page.setScaleX((position != 0 && position != 1) ? percentage : 1); + page.setScaleY((position != 0 && position != 1) ? percentage : 1); + } + + private void setRotation(View page, float position, float percentage) { + if (position > 0) { + page.setRotationY(-180 * (percentage + 1)); + } else { + page.setRotationY(180 * (percentage + 1)); + } + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/DataUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/DataUtils.java new file mode 100644 index 00000000..cb7a0773 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/DataUtils.java @@ -0,0 +1,47 @@ +package org.buildmlearn.toolkit.flashcardtemplate.data; + +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 10/8/16. + */ + +/** + * @brief Contains xml data utils for flash card template's simulator. + */ +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(org.buildmlearn.toolkit.flashcardtemplate.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/flashcardtemplate/data/FetchXMLTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FetchXMLTask.java new file mode 100644 index 00000000..25a3fa79 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FetchXMLTask.java @@ -0,0 +1,144 @@ +package org.buildmlearn.toolkit.flashcardtemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.os.AsyncTask; + +import org.buildmlearn.toolkit.flashcardtemplate.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 10/8/16. + */ + +/** + * @brief Used to parse XML and save in database for flash card template's simulator. + */ + +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 saveFlashData(ArrayList Flashs) { + + Vector cVVector = new Vector<>(Flashs.size()); + + for (int i = 0; i < Flashs.size(); i++) { + + String question; + String answer; + String hint; + String base64; + + FlashModel FlashFlash = Flashs.get(i); + + question = FlashFlash.getQuestion(); + answer = FlashFlash.getAnswer(); + hint = FlashFlash.getHint(); + base64 = FlashFlash.getBase64(); + + ContentValues FlashValues = new ContentValues(); + + FlashValues.put(FlashContract.FlashCards.QUESTION, question); + FlashValues.put(FlashContract.FlashCards.ANSWER, answer); + FlashValues.put(FlashContract.FlashCards.HINT, hint); + FlashValues.put(FlashContract.FlashCards.BASE64, base64); + + cVVector.add(FlashValues); + } + // add to database + if (cVVector.size() > 0) { + ContentValues[] cvArray = new ContentValues[cVVector.size()]; + cVVector.toArray(cvArray); + FlashDb db = new FlashDb(mContext); + db.open(); + db.bulkInsertFlashCards(cvArray); + db.close(); + } + } + + @Override + protected Void doInBackground(String... params) { + + if (params.length == 0) { + return null; + } + String fileName = params[0]; + 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++) { + FlashModel app = new FlashModel(); + + Node child = childNodes.item(i); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element2 = (Element) child; + + app.setQuestion(getValue("question", element2)); + app.setAnswer(getValue("answer", element2)); + app.setHint(getValue("hint", element2)); + app.setBase64(getValue("image", element2)); + } + mList.add(app); + } + saveFlashData(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/flashcardtemplate/data/FlashContract.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashContract.java new file mode 100644 index 00000000..65c719cd --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashContract.java @@ -0,0 +1,24 @@ +package org.buildmlearn.toolkit.flashcardtemplate.data; + +import android.provider.BaseColumns; + +/** + * Created by Anupam (opticod) on 10/8/16. + */ + +/** + * @brief Contains database contracts for flash card template's simulator. + */ +class FlashContract { + + public static final class FlashCards implements BaseColumns { + + public static final String TABLE_NAME = "cards"; + + public static final String QUESTION = "question"; + public static final String ANSWER = "answer"; + public static final String HINT = "hint"; + public static final String BASE64 = "base64"; + + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashDBHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashDBHelper.java new file mode 100644 index 00000000..3f0e28b1 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashDBHelper.java @@ -0,0 +1,43 @@ +package org.buildmlearn.toolkit.flashcardtemplate.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.buildmlearn.toolkit.flashcardtemplate.data.FlashContract.FlashCards; + +/** + * Created by Anupam (opticod) on 10/8/16. + */ + +/** + * @brief DatabaseHelper for flash card template's simulator. + */ +class FlashDBHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "learn_flash.db"; + private static final int DATABASE_VERSION = 1; + + public FlashDBHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + final String SQL_CREATE__TABLE_A = "CREATE TABLE " + FlashCards.TABLE_NAME + " (" + + FlashCards._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + FlashCards.QUESTION + " TEXT," + + FlashCards.ANSWER + " TEXT," + + FlashCards.HINT + " TEXT," + + FlashCards.BASE64 + " TEXT )"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE_A); + + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + FlashCards.TABLE_NAME); + onCreate(sqLiteDatabase); + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashDb.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashDb.java new file mode 100644 index 00000000..9aabd121 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashDb.java @@ -0,0 +1,83 @@ +package org.buildmlearn.toolkit.flashcardtemplate.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.flashcardtemplate.data.FlashContract.FlashCards; + +/** + * Created by Anupam (opticod) on 10/8/16. + */ + +/** + * @brief Contains database util functions for flash card template's simulator. + */ +public class FlashDb { + + private static final String EQUAL = " == "; + private final FlashDBHelper dbHelper; + private SQLiteDatabase db; + + public FlashDb(Context context) { + dbHelper = new FlashDBHelper(context); + } + + public void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public void close() { + dbHelper.close(); + } + + public Cursor getFlashCursorById(int id) { + + String selection = FlashCards._ID + EQUAL + id; + + return db.query( + FlashCards.TABLE_NAME, + null, + selection, + null, + null, + null, + null + ); + } + + public long getCountFlashCards() { + + return DatabaseUtils.queryNumEntries(db, + FlashCards.TABLE_NAME); + } + + public int bulkInsertFlashCards(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(FlashCards.TABLE_NAME, null, value); + if (_id != -1) { + returnCount++; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + return returnCount; + } + + public void deleteAll() { + db.delete(FlashContract.FlashCards.TABLE_NAME, null, null); + db.execSQL("delete from sqlite_sequence where name='" + FlashContract.FlashCards.TABLE_NAME + "';"); + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashModel.java new file mode 100644 index 00000000..f717f415 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/data/FlashModel.java @@ -0,0 +1,86 @@ +package org.buildmlearn.toolkit.flashcardtemplate.data; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Created by Anupam (opticod) on 10/8/16. + */ + +/** + * @brief Model used to save flash entries in database for flash card template's simulator. + */ +public class FlashModel implements Parcelable { + public final static Creator CREATOR = new Creator() { + @Override + public FlashModel createFromParcel(Parcel parcel) { + return new FlashModel(parcel); + } + + @Override + public FlashModel[] newArray(int size) { + return new FlashModel[size]; + } + }; + + private String question; + private String answer; + private String hint; + private String base64; + + private FlashModel(Parcel in) { + this.question = in.readString(); + this.answer = in.readString(); + this.hint = in.readString(); + this.base64 = in.readString(); + } + + public FlashModel() { + + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(question); + dest.writeString(answer); + dest.writeString(hint); + dest.writeString(base64); + } + + public String getQuestion() { + return question; + } + + public void setQuestion(String question) { + this.question = question; + } + + public String getAnswer() { + return answer; + } + + public void setAnswer(String answer) { + this.answer = answer; + } + + public String getBase64() { + return base64; + } + + public void setBase64(String base64) { + this.base64 = base64; + } + + public String getHint() { + return hint; + } + + public void setHint(String hint) { + this.hint = hint; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/fragment/LastFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/fragment/LastFragment.java new file mode 100644 index 00000000..7a554fd4 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/fragment/LastFragment.java @@ -0,0 +1,90 @@ +package org.buildmlearn.toolkit.flashcardtemplate.fragment; + +import android.app.FragmentManager; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +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; + +/** + * Created by anupam on 10/8/16. + */ + +/** + * @brief Fragment for displaying score to user in flash card template's simulator. + */ +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.fragment_last_flash, container, false); + + Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + toolbar.setTitle(getResources().getString(R.string.main_title_spell)); + 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; + 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; + } + }); + + 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/flashcardtemplate/fragment/MainFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/fragment/MainFragment.java new file mode 100644 index 00000000..219b80ac --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/fragment/MainFragment.java @@ -0,0 +1,328 @@ +package org.buildmlearn.toolkit.flashcardtemplate.fragment; + +import android.app.FragmentManager; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +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.view.PagerAdapter; +import android.support.v4.view.ViewPager; +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.util.Base64; +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.view.animation.AccelerateDecelerateInterpolator; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.flashcardtemplate.Constants; +import org.buildmlearn.toolkit.flashcardtemplate.animations.FlipPageTransformer; +import org.buildmlearn.toolkit.flashcardtemplate.data.FlashDb; +import org.buildmlearn.toolkit.flashcardtemplate.data.FlashModel; +import org.buildmlearn.toolkit.flashcardtemplate.widgets.FixedSpeedScroller; + +import java.lang.reflect.Field; +import java.util.Locale; + +/** + * Created by anupam on 10/8/16. + */ + +/** + * @brief Fragment containing the flash cards in dictation template's simulator. + */ +public class MainFragment extends Fragment implements NavigationView.OnNavigationItemSelectedListener { + + private ViewPager viewPager; + private FlashDb db; + private View rootView; + + public static Fragment newInstance() { + return new MainFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + rootView = inflater.inflate(R.layout.fragment_main_flash, 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.setTitle(getResources().getString(R.string.main_title_spell)); + + 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; + 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; + } + }); + + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(getActivity() + , drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); + assert drawer != null; + drawer.addDrawerListener(toggle); + toggle.syncState(); + + NavigationView navigationView = (NavigationView) rootView.findViewById(R.id.nav_view); + assert navigationView != null; + navigationView.setNavigationItemSelectedListener(this); + + Context mContext = getActivity(); + + db = new FlashDb(mContext); + db.open(); + + Bundle extras = getArguments(); + String FlashId = "1"; + if (extras != null) { + FlashId = extras.getString(Intent.EXTRA_TEXT); + } + + Menu m = navigationView.getMenu(); + SubMenu topChannelMenu = m.addSubMenu("Flash Cards"); + final long numFlash = db.getCountFlashCards(); + + for (int i = 1; i <= numFlash; i++) { + topChannelMenu.add(String.format(Locale.getDefault(), "Flash Card %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)); + + 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(); + + return false; + } + }); + } + + MenuItem mi = m.getItem(m.size() - 1); + mi.setTitle(mi.getTitle()); + + + Cursor flash_cursor = db.getFlashCursorById(Integer.parseInt(FlashId)); + flash_cursor.moveToFirst(); + String question = flash_cursor.getString(Constants.COL_QUESTION); + String answer = flash_cursor.getString(Constants.COL_ANSWER); + String hint = flash_cursor.getString(Constants.COL_HINT); + String base64 = flash_cursor.getString(Constants.COL_BASE64); + + assert rootView.findViewById(R.id.intro_number) != null; + ((TextView) rootView.findViewById(R.id.intro_number)).setText(String.format(Locale.ENGLISH, "Card #%d of %d", Integer.parseInt(FlashId), numFlash)); + assert rootView.findViewById(R.id.question) != null; + ((TextView) rootView.findViewById(R.id.question)).setText(question); + assert rootView.findViewById(R.id.hint) != null; + ((TextView) rootView.findViewById(R.id.hint)).setText(String.format(Locale.ENGLISH, "Hint : %s", hint)); + + Button prv = (Button) rootView.findViewById(R.id.previous); + Button flip = (Button) rootView.findViewById(R.id.flip); + Button next = (Button) rootView.findViewById(R.id.next); + viewPager = (ViewPager) rootView.findViewById(R.id.viewpagerflash); + + + if (null != FlashId && FlashId.equals("1")) { + assert prv != null; + prv.setEnabled(false); + prv.setTextColor(ContextCompat.getColor(mContext, R.color.grey_shade_4_flash)); + } + + viewPager.setPageTransformer(true, new FlipPageTransformer()); + + try { + Field mScroller; + mScroller = ViewPager.class.getDeclaredField("mScroller"); + mScroller.setAccessible(true); + FixedSpeedScroller scroller = new FixedSpeedScroller(mContext, new AccelerateDecelerateInterpolator()); + mScroller.set(viewPager, scroller); + } catch (Exception e) { + e.printStackTrace(); + } + + final String finalFlashId1 = FlashId; + assert prv != null; + prv.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + long nextFlashId = Integer.parseInt(finalFlashId1) - 1; + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(nextFlashId)); + + 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(); + + } + }); + + final String finalFlashId = FlashId; + assert next != null; + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + long nextFlashId = Integer.parseInt(finalFlashId) + 1; + if (nextFlashId <= numFlash) { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(nextFlashId)); + + 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(); + + + } else { + + Bundle arguments = new Bundle(); + Fragment frag = LastFragment.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(); + + } + } + }); + + assert flip != null; + flip.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (viewPager.getCurrentItem() == 0) + viewPager.setCurrentItem(1, true); + else + viewPager.setCurrentItem(0, true); + } + }); + + FlashModel mFlash = new FlashModel(); + mFlash.setQuestion(question); + mFlash.setAnswer(answer); + mFlash.setHint(hint); + mFlash.setBase64(base64); + setAdapterData(mFlash); + + return rootView; + } + + private void setAdapterData(FlashModel mFlash) { + MyPagerAdapter adapter = new MyPagerAdapter(mFlash); + viewPager.setAdapter(adapter); + } + + @Override + public void onDestroy() { + db.close(); + super.onDestroy(); + } + + @Override + public boolean onNavigationItemSelected(MenuItem item) { + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + assert drawer != null; + drawer.closeDrawer(GravityCompat.START); + return true; + } + + class MyPagerAdapter extends PagerAdapter { + + final FlashModel model; + + public MyPagerAdapter(FlashModel mFlash) { + this.model = mFlash; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + View cardView; + + if (position == 0) { + cardView = LayoutInflater.from(getContext()).inflate(R.layout.question_layout_flash_card, container, false); + ImageView image = (ImageView) cardView.findViewById(R.id.questionimage); + + if (model.getBase64() != null && !model.getBase64().equals("")) { + byte[] decodedString = Base64.decode(model.getBase64(), + Base64.DEFAULT); + Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, + 0, decodedString.length); + image.setImageBitmap(decodedByte); + } else { + image.setImageResource(R.drawable.image_quiz); + } + } else { + cardView = LayoutInflater.from(getContext()).inflate(R.layout.answer_layout_flash_card, container, false); + TextView text = (TextView) cardView.findViewById(R.id.answertext); + + text.setText(model.getAnswer()); + } + + int width = getContext().getResources().getDisplayMetrics().widthPixels - getContext().getResources().getDimensionPixelSize(R.dimen.material_button_height_flash); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, width); + cardView.findViewById(R.id.cardview).setLayoutParams(params); + + container.addView(cardView); + return cardView; + } + + @Override + public int getCount() { + return 2; + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return object == view; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/fragment/SplashFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/fragment/SplashFragment.java new file mode 100644 index 00000000..94901509 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/fragment/SplashFragment.java @@ -0,0 +1,68 @@ +package org.buildmlearn.toolkit.flashcardtemplate.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.flashcardtemplate.Constants; +import org.buildmlearn.toolkit.flashcardtemplate.data.DataUtils; +import org.buildmlearn.toolkit.flashcardtemplate.data.FetchXMLTask; +import org.buildmlearn.toolkit.flashcardtemplate.data.FlashDb; +import org.buildmlearn.toolkit.views.TextViewPlus; + +/** + * Created by Anupam (opticod) on 10/8/16. + */ + +/** + * @brief Splash intro Fragment for flash card template's simulator. + */ +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_flash)); + + 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(); + } + }); + + FlashDb db = new FlashDb(mActivity); + db.open(); + db.deleteAll(); + + long numColumns = db.getCountFlashCards(); + 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/widgets/FixedSpeedScroller.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/widgets/FixedSpeedScroller.java new file mode 100644 index 00000000..28777eee --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/flashcardtemplate/widgets/FixedSpeedScroller.java @@ -0,0 +1,25 @@ +package org.buildmlearn.toolkit.flashcardtemplate.widgets; + +import android.content.Context; +import android.view.animation.Interpolator; +import android.widget.Scroller; + +public class FixedSpeedScroller extends Scroller { + + private final int mDuration = 500; + + public FixedSpeedScroller(Context context, Interpolator interpolator) { + super(context, interpolator); + } + + + @Override + public void startScroll(int startX, int startY, int dx, int dy, int duration) { + super.startScroll(startX, startY, dx, dy, mDuration); + } + + @Override + public void startScroll(int startX, int startY, int dx, int dy) { + super.startScroll(startX, startY, dx, dy, mDuration); + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/DraftsFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/DraftsFragment.java index e800ffc5..6349dae5 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/DraftsFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/DraftsFragment.java @@ -7,6 +7,7 @@ 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; @@ -46,6 +47,10 @@ /** * Created by scopeinfinity on 10/3/16. */ + +/** + * @brief Fragment used to save drafts. + */ public class DraftsFragment extends Fragment implements AbsListView.OnItemClickListener { private static final String TAG = "Draft Project Fragment"; @@ -85,8 +90,7 @@ public void onCreate(Bundle savedInstanceState) { @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); } /** @@ -112,7 +116,7 @@ public boolean onItemLongClick(AdapterView parent, View view, int position, l selectedView = view; selectedPosition = position; Log.d(TAG, "Position: " + selectedPosition); - view.setBackgroundColor(getResources().getColor(R.color.color_divider)); + view.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.color_divider)); changeColorScheme(); } return true; @@ -164,7 +168,7 @@ public void onResume() { super.onResume(); } - protected void reloadContent() { + private void reloadContent() { draftProjects.clear(); @@ -180,8 +184,8 @@ protected void reloadContent() { 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 { @@ -190,13 +194,7 @@ protected void reloadContent() { doc.getDocumentElement().normalize(); Log.d("Files", "Root element :" + doc.getDocumentElement().getAttribute("type")); draftProjects.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(); } } @@ -217,9 +215,9 @@ public int compare(SavedProject f1, SavedProject f2) { *

* 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(getActivity(), R.color.color_primary); + int primaryColorDark = ContextCompat.getColor(getActivity(), R.color.color_primary_dark); ((AppCompatActivity) activity).getSupportActionBar().setBackgroundDrawable(new ColorDrawable(primaryColor)); ThemeSingleton.get().positiveColor = ColorStateList.valueOf(primaryColor); ThemeSingleton.get().neutralColor = ColorStateList.valueOf(primaryColor); @@ -238,9 +236,9 @@ public void restoreColorScheme() { *

* 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(getActivity(), R.color.color_primary_dark); + int primaryColorDark = ContextCompat.getColor(getActivity(), R.color.color_selected_dark); ((AppCompatActivity) activity).getSupportActionBar().setBackgroundDrawable(new ColorDrawable(primaryColor)); ThemeSingleton.get().positiveColor = ColorStateList.valueOf(primaryColor); ThemeSingleton.get().neutralColor = ColorStateList.valueOf(primaryColor); @@ -361,7 +359,7 @@ private void deleteAllDrafts() { /** * @brief Removes selected color from the selected ListView item when switching from edit mode to normal mode */ - public void restoreSelectedView() { + private void restoreSelectedView() { if (selectedView != null) { selectedView.setBackgroundResource(0); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadApkFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadApkFragment.java index 8c7c9982..1f9346a7 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadApkFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/fragment/LoadApkFragment.java @@ -78,9 +78,9 @@ public void onCreate(Bundle savedInstanceState) { } Log.d("Files", "Size: " + file.length); - for (int i = 0; i < file.length; i++) { - Log.d(TAG, file[i].getAbsolutePath()); - File apkFile = new File(file[i].getAbsolutePath()); + for (File aFile : file) { + Log.d(TAG, aFile.getAbsolutePath()); + File apkFile = new File(aFile.getAbsolutePath()); savedApis.add(new SavedApi(apkFile, apkFile.getName(), apkFile.lastModified(), apkFile.getAbsolutePath())); } @@ -99,8 +99,7 @@ public int compare(SavedApi f1, SavedApi 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); } /** @@ -182,9 +181,9 @@ public void onResume() { } Log.d("Files", "Size: " + file.length); - for (int i = 0; i < file.length; i++) { - if (file[i].getName().contains(".apk")) { - File apkFile = new File(file[i].getAbsolutePath()); + for (File aFile : file) { + if (aFile.getName().contains(".apk")) { + File apkFile = new File(aFile.getAbsolutePath()); savedApis.add(new SavedApi(apkFile, apkFile.getName(), apkFile.lastModified(), apkFile.getAbsolutePath())); } } @@ -206,9 +205,9 @@ public int compare(SavedApi f1, SavedApi f2) { *

* 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(getActivity(), R.color.color_primary); + int primaryColorDark = ContextCompat.getColor(getActivity(), R.color.color_primary_dark); ((AppCompatActivity) activity).getSupportActionBar().setBackgroundDrawable(new ColorDrawable(primaryColor)); ThemeSingleton.get().positiveColor = ColorStateList.valueOf(primaryColor); ThemeSingleton.get().neutralColor = ColorStateList.valueOf(primaryColor); @@ -227,9 +226,9 @@ public void restoreColorScheme() { *

* 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(getActivity(), R.color.color_primary_dark); + int primaryColorDark = ContextCompat.getColor(getActivity(), R.color.color_selected_dark); ((AppCompatActivity) activity).getSupportActionBar().setBackgroundDrawable(new ColorDrawable(primaryColor)); ThemeSingleton.get().positiveColor = ColorStateList.valueOf(primaryColor); ThemeSingleton.get().neutralColor = ColorStateList.valueOf(primaryColor); @@ -318,7 +317,7 @@ private void deleteItem(int selectedPosition) { /** * @brief Removes selected color from the selected ListView item when switching from edit mode to normal mode */ - public void restoreSelectedView() { + private void restoreSelectedView() { if (selectedView != null) { selectedView.setBackgroundResource(0); } 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 0cfcc9fd..77a46a82 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 @@ -3,13 +3,12 @@ import android.app.Activity; import android.app.Fragment; import android.content.Intent; -import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.graphics.drawable.ColorDrawable; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.content.ContextCompat; -import android.preference.PreferenceManager; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.LayoutInflater; @@ -62,14 +61,6 @@ public class LoadProjectFragment extends Fragment implements AbsListView.OnItemC private ArrayList savedProjects; private View selectedView = null; - private SharedPreferences prefs; - private static final String PREF_SORT = "sortType"; - public static final int SORT_TYPE_MODIFIED = 0; - public static final int SORT_TYPE_NAME = 1; - public static final int SORT_TYPE_AUTHOR = 2; - - private int selectedPosition = -1; - /** * {@inheritDoc} */ @@ -80,7 +71,6 @@ public void onCreate(Bundle savedInstanceState) { mToolkit = (ToolkitApplication) getActivity().getApplicationContext(); activity = getActivity(); savedProjects = new ArrayList<>(); - prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); String path = mToolkit.getSavedDir(); Log.d("Files", "Path: " + path); @@ -110,6 +100,13 @@ public void onCreate(Bundle savedInstanceState) { } } + Collections.sort(savedProjects, new Comparator() { + public int compare(SavedProject f1, SavedProject f2) { + return Long.valueOf(f1.getFile().lastModified()).compareTo(f2.getFile().lastModified()); + } + }); + + Collections.reverse(savedProjects); } /** @@ -128,11 +125,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, public void onViewCreated(View view, Bundle savedInstanceState) { mAdapter = new SavedProjectAdapter(getActivity(), savedProjects); mListView = (AbsListView) view.findViewById(android.R.id.list); - mAdapter.setSortType(prefs.getInt(PREF_SORT, SORT_TYPE_MODIFIED)); - mAdapter.sort(); setAdapter(mAdapter); - - mListView.setOnItemClickListener(this); mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override @@ -225,7 +218,13 @@ public void onResume() { } } - mAdapter.sort(); + Collections.sort(savedProjects, new Comparator() { + public int compare(SavedProject f1, SavedProject f2) { + return Long.valueOf(f1.getFile().lastModified()).compareTo(f2.getFile().lastModified()); + } + }); + + Collections.reverse(savedProjects); mAdapter.notifyDataSetChanged(); } super.onResume(); @@ -274,18 +273,14 @@ private void changeColorScheme() { activity.invalidateOptionsMenu(); } - /** + /** * {@inheritDoc} */ @Override - - public void onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - menu.clear(); + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); if (showTemplateSelectedMenu) { activity.getMenuInflater().inflate(R.menu.menu_project_selected, menu); - } else { - activity.getMenuInflater().inflate(R.menu.menu_project, menu); } } @@ -299,43 +294,35 @@ public boolean onOptionsItemSelected(MenuItem item) { switch (id) { case R.id.action_delete: - final MaterialDialog dialogDelete = new MaterialDialog.Builder(activity) + 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(); - dialogDelete.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - dialogDelete.dismiss(); - deleteItem(selectedPosition); + dialog.dismiss(); + deleteItem(mAdapter.getSelectedPosition()); restoreSelectedView(); } }); - dialogDelete.show(); + dialog.show(); break; - case R.id.action_sort: - - final MaterialDialog dialogSort = new MaterialDialog.Builder(activity) - .title(R.string.dialog_sort_title) - .items(R.array.project_sort) - .itemsCallbackSingleChoice(mAdapter.getSortType(), new MaterialDialog.ListCallbackSingleChoice() { - @Override - public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) { - mAdapter.setSortType(which); - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(PREF_SORT, which); - editor.commit(); - mAdapter.sort(); - mAdapter.notifyDataSetChanged(); - return true; - } - }) - .build(); - - dialogSort.show(); + case R.id.action_share: + + SavedProject project = savedProjects.get(mAdapter.getSelectedPosition()); + File file = new File(project.getFile().getPath()); + + Uri fileUri = Uri.fromFile(file); + ArrayList uris = new ArrayList<>(); + Intent sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); + sendIntent.setType("application/zip"); + uris.add(fileUri); + sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); + startActivity(Intent.createChooser(sendIntent, null)); break; default: //do nothing break; 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 36f9e970..272861cf 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 @@ -26,6 +26,8 @@ import org.buildmlearn.toolkit.adapter.NavigationDrawerMenuAdapter; import org.buildmlearn.toolkit.model.Section; +import java.util.Locale; + /** * Fragment used for managing interactions for and presentation of a navigation drawer. * See the @@ -122,7 +124,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, View menuHeaderView = inflater.inflate(R.layout.listview_header_navigation_drawer, mDrawerListView, false); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); TextView name = (TextView) menuHeaderView.findViewById(R.id.name); - name.setText("Welcome " + prefs.getString(getString(R.string.key_user_name), "")); + name.setText(String.format(Locale.ENGLISH, "Welcome %s", prefs.getString(getString(R.string.key_user_name), ""))); mDrawerListView.addHeaderView(menuHeaderView, null, false); mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override @@ -142,8 +144,8 @@ public void onItemClick(AdapterView parent, View view, int position, long id) }); NavigationDrawerMenuAdapter adapter = new NavigationDrawerMenuAdapter(getActivity().getApplicationContext(), inflater); menus = Section.values(); - for (int i = 0; i < menus.length; i++) { - menus[i].setIsSelected(false); + for (Section menu : menus) { + menu.setIsSelected(false); } if (menus.length > 0) { menus[selectedSectionMenu].setIsSelected(true); @@ -153,7 +155,7 @@ public void onItemClick(AdapterView parent, View view, int position, long id) return mDrawerListView; } - private boolean isDrawerOpen() { + public boolean isDrawerOpen() { return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView); } @@ -229,7 +231,7 @@ public void onDrawerStateChanged(int newState) { SharedPreferences sp = PreferenceManager .getDefaultSharedPreferences(getActivity()); TextView name = (TextView) mFragmentContainerView.findViewById(R.id.name); - name.setText("Welcome " + sp.getString(getString(R.string.key_user_name), "")); + name.setText(String.format(Locale.ENGLISH, "Welcome %s", sp.getString(getString(R.string.key_user_name), ""))); } }; @@ -344,6 +346,10 @@ private ActionBar getActionBar() { return ((AppCompatActivity) getActivity()).getSupportActionBar(); } + public void closeDrawer() { + mDrawerLayout.closeDrawers(); + } + /** * Callbacks interface that all activities using this fragment must implement. */ 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 4f127223..5e735e26 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 @@ -127,6 +127,17 @@ public void onSuccess(File assetFile) { getActivity().startActivity(intentProject); } + @Override + public void onFail() { + processDiaglog.dismiss(); + final MaterialDialog dialog = new MaterialDialog.Builder(getActivity()) + .title(R.string.dialog_restore_title) + .content(R.string.dialog_restore_failed) + .positiveText(R.string.info_template_ok) + .build(); + dialog.show(); + } + @Override public void onFail(Exception e) { processDiaglog.dismiss(); 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 index 03169160..e2836837 100644 --- 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 @@ -5,6 +5,10 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Constants used in info template's simulator relating databases. + */ public class Constants { public static final String[] INFO_COLUMNS = { InfoContract.Info.TABLE_NAME + "." + InfoContract.Info._ID, 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 index ac58766d..24901aa9 100644 --- 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 @@ -15,6 +15,10 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Custom Adapter for info template's simulator. + */ public class InfoArrayAdapter extends CursorAdapter { public InfoArrayAdapter(Context context) { 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 index 54334d52..50311e87 100644 --- 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 @@ -14,6 +14,10 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Contains xml data utils for info template's simulator. + */ public class DataUtils { public static String[] readTitleAuthor() { 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 index 2c1cb12f..98b6f3c3 100644 --- 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 @@ -24,6 +24,10 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Used to parse XML and save in database for info template's simulator. + */ public class FetchXMLTask extends AsyncTask { private final Context mContext; 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 index 0beeb43f..3f9a7a10 100644 --- 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 @@ -6,6 +6,9 @@ * Created by Anupam (opticod) on 20/6/16. */ +/** + * @brief Contains database contracts for info template's simulator. + */ public class InfoContract { public static final class Info implements BaseColumns { 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 index 64966fcd..ae02d131 100644 --- 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 @@ -10,6 +10,9 @@ * Created by Anupam (opticod) on 20/6/16. */ +/** + * @brief DatabaseHelper for info template's simulator. + */ class InfoDBHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "mLearning.db"; 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 index 8a028f0e..b8ba86a4 100644 --- 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 @@ -11,6 +11,10 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Contains database util functions for info template's simulator. + */ public class InfoDb { private static final String EQUAL = " == "; @@ -25,10 +29,6 @@ public void open() throws SQLException { db = dbHelper.getWritableDatabase(); } - public boolean isOpen() { - return db.isOpen(); - } - public void close() { dbHelper.close(); } 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 index 201f5005..a7e41ead 100644 --- 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 @@ -6,8 +6,12 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Model used to save info entries in database for info template's simulator. + */ public class InfoModel implements Parcelable { - public final Creator CREATOR = new Creator() { + public final static Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public InfoModel createFromParcel(Parcel parcel) { return new InfoModel(parcel); @@ -24,11 +28,6 @@ public InfoModel[] newArray(int size) { 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(); 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 index f9fa9234..638abcaa 100644 --- 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 @@ -27,6 +27,10 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Fragment for details of items in info template's simulator. + */ public class DetailActivityFragment extends Fragment implements LoaderCallbacks { private static final int DETAIL_LOADER = 0; @@ -83,6 +87,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { welcomeAlert.show(); assert welcomeAlert.findViewById(android.R.id.message) != null; assert welcomeAlert.findViewById(android.R.id.message) != null; + assert ((TextView) welcomeAlert.findViewById(android.R.id.message)) != null; ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); break; default: //do nothing 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 index 711ddb62..b7616f89 100644 --- 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 @@ -31,6 +31,11 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Fragment containing the list of items in info template's simulator. + */ + public class MainActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks { private static final String SELECTED_KEY = "selected_position"; @@ -92,6 +97,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { builder.setPositiveButton("OK", null); AlertDialog welcomeAlert = builder.create(); welcomeAlert.show(); + assert welcomeAlert.findViewById(android.R.id.message) != null; assert ((TextView) welcomeAlert.findViewById(android.R.id.message)) != null; ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); break; 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 index 144e3acc..7658e4ed 100644 --- 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 @@ -19,6 +19,10 @@ /** * Created by Anupam (opticod) on 20/6/16. */ + +/** + * @brief Splash intro Fragment for info template's simulator. + */ public class SplashFragment extends Fragment { public static Fragment newInstance(String path) { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/Constants.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/Constants.java new file mode 100644 index 00000000..e0ac6b75 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/Constants.java @@ -0,0 +1,17 @@ +package org.buildmlearn.toolkit.learnspelling; + +/** + * Created by Anupam (opticod) on 31/5/16. + */ + +/** + * @brief Constants used in spell template's simulator relating databases. + */ +public class Constants { + public static final int COL_WORD = 1; + public static final int COL_MEANING = 2; + public static final int COL_ANSWERED = 3; + public static final int COL_ATTEMPTED = 4; + public static String XMLFileName = "spelling_content.xml"; + +} 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 deleted file mode 100644 index 78d1b1f4..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/DataManager.java +++ /dev/null @@ -1,169 +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.learnspelling; - -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.IOException; -import java.util.ArrayList; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - - -/** - * @brief Simulator code for Learn Spelling Template - */ -public class DataManager { - private static DataManager instance = null; - private String mTitle = null; - private String mAuthor = null; - private ArrayList mList = null; - private int countIndex = 0; - private int countCorrect = 0; - private int countWrong = 0; - - public static DataManager getInstance() { - if (instance == null) { - instance = new DataManager(); - } - 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 = nodeList.item(0); - - return node.getNodeValue(); - } - } - - public void readXml(String filePath) { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - - dbf.setValidating(false); - - DocumentBuilder db; - Document doc; - try { - mList = new ArrayList<>(); - File fXmlFile = new File(filePath); - db = dbf.newDocumentBuilder(); - doc = db.parse(fXmlFile); - doc.normalize(); - mTitle = doc.getElementsByTagName("title").item(0).getChildNodes() - .item(0).getNodeValue(); - mAuthor = doc.getElementsByTagName("name").item(0).getChildNodes() - .item(0).getNodeValue(); - NodeList childNodes = doc.getElementsByTagName("item"); - for (int i = 0; i < childNodes.getLength(); i++) { - WordModel app = new WordModel(); - - Node child = childNodes.item(i); - - if (child.getNodeType() == Node.ELEMENT_NODE) { - Element element2 = (Element) child; - - app.setWord(getValue("word", element2)); - app.setDescription(getValue("meaning", element2)); - - } - mList.add(app); - - } - } catch (ParserConfigurationException | IOException | SAXException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } - - } - - public ArrayList getList() { - - return mList; - } - - public String getTitle() { - return mTitle; - } - - public String getAuthor() { - return mAuthor; - } - - public int getActiveWordCount() { - return countIndex; - - } - - public void increaseCount() { - countIndex++; - } - - public void incrementCorrect() { - countCorrect++; - } - - public int getCorrect() { - return countCorrect; - } - - public int getWrong() { - return countWrong; - } - - public void incrementWrong() { - countWrong++; - } - - public void reset() { - countCorrect = 0; - if (mList!=null) - mList.clear(); - countIndex = 0; - countWrong = 0; - } - -} 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 deleted file mode 100644 index 1208731d..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/ResultActivity.java +++ /dev/null @@ -1,121 +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.learnspelling; - -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; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.constant.Constants; -import org.buildmlearn.toolkit.flashcardtemplate.StartFragment; - -import java.util.Locale; - -/** - * @brief Simulator code for Learn Spelling Template - */ -public class ResultActivity extends Fragment { - private DataManager mDataManager; - private TextToSpeech textToSpeech; - private int unanswered, wrong, correct; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - View view = inflater.inflate(R.layout.spelling_fragment_finish, container, false); - mDataManager = DataManager.getInstance(); - 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; - - mTv_Correct.setText(getString(R.string.correct) + " " + correct); - - mTv_Wrong.setText(getString(R.string.wrong_spelled) + " " + wrong); - mTv_Unanswered.setText(getString(R.string.unanswered) + " " - + unanswered); - textToSpeech = new TextToSpeech(getActivity(), - new TextToSpeech.OnInitListener() { - - @Override - public void onInit(int arg0) { - if (arg0 == TextToSpeech.SUCCESS) { - textToSpeech.setLanguage(Locale.US); - String speechText = getString(R.string.correct) - + " " + correct - + getString(R.string.wrong_spelled) + " " - + wrong + getString(R.string.unanswered) - + " " + unanswered; - convertTextToSpeech(speechText); - } - } - }); - - - view.findViewById(R.id.btn_exit).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - getActivity().finish(); - } - }); - - view.findViewById(R.id.btn_restart).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mDataManager.reset(); - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, SpellingMainFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), StartFragment.TAG).addToBackStack(null).commit(); -//t - } - }); - - return view; - } - - - @Override - public void onStop() { - super.onStop(); - textToSpeech.shutdown(); - } - - private void convertTextToSpeech(String text) { - - textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null); - } - -} 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 deleted file mode 100644 index 0e393419..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingActivity.java +++ /dev/null @@ -1,217 +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.learnspelling; - -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -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; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.EditText; -import android.widget.SeekBar; -import android.widget.TextView; -import android.widget.Toast; - -import org.buildmlearn.toolkit.R; - -import java.util.ArrayList; -import java.util.Locale; - -/** - * @brief Simulator code for Learn Spelling Template - */ -public class SpellingActivity extends Fragment implements - TextToSpeech.OnInitListener { - private TextToSpeech textToSpeech; - private DataManager mManager; - private ArrayList mWordList; - private int count; - private AlertDialog mAlert; - private TextView mTv_WordNumber; - private Button mBtn_Spell, mBtn_Skip; - private EditText mEt_Spelling; - private SeekBar mSb_SpeechRate; - - private static final float MIN_SPEECH_RATE = 0.01f; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - View view = inflater.inflate(R.layout.spelling_fragment_spelling, container, false); - - mBtn_Spell = (Button) view.findViewById(R.id.btn_ready); - - mBtn_Skip = (Button) view.findViewById(R.id.btn_skip); - mSb_SpeechRate = (SeekBar) view.findViewById(R.id.sb_speech); - - mTv_WordNumber = (TextView) view.findViewById(R.id.tv_word_number); - textToSpeech = new TextToSpeech(getActivity(), this); - mManager = DataManager.getInstance(); - mWordList = mManager.getList(); - count = mManager.getActiveWordCount(); - mTv_WordNumber.setText("Word #" + (count + 1) + " of " - + mWordList.size()); - - view.findViewById(R.id.btn_skip).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (count < mWordList.size() - 1) { - - count++; - mManager.increaseCount(); - mTv_WordNumber.setText("Word #" + (count + 1) + " of " - + mWordList.size()); - mBtn_Spell.setEnabled(false); - mBtn_Skip.setEnabled(false); - mBtn_Skip.setTextColor(Color.WHITE); - mBtn_Spell.setTextColor(Color.WHITE); - } else { - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new ResultActivity()).addToBackStack(null).commit(); - } - } - }); - view.findViewById(R.id.btn_speak).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - convertTextToSpeech(mWordList.get(count).getWord()); - mBtn_Spell.setEnabled(true); - mBtn_Skip.setEnabled(true); - mBtn_Skip.setTextColor(Color.RED); - mBtn_Spell.setTextColor(Color.GREEN); - } - }); - view.findViewById(R.id.btn_ready).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - LayoutInflater factory = LayoutInflater.from(getActivity()); - final View textEntryView = factory.inflate( - R.layout.spelling_dialog_spellinginput, null); - Builder builder = new Builder(getActivity()); - mAlert = builder.create(); - mAlert.setCancelable(true); - mAlert.setView(textEntryView, 10, 10, 10, 10); - if (mAlert != null && !mAlert.isShowing()) { - mAlert.show(); - } - mEt_Spelling = (EditText) mAlert.findViewById(R.id.et_spelling); - Button mBtn_Submit = (Button) mAlert.findViewById(R.id.btn_submit); - mBtn_Submit.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - submit(); - } - }); - } - }); - - return view; - } - - - /** - * Releases the resources used by the TextToSpeech engine. It is good - * practice for instance to call this method in the onDestroy() method of an - * Activity so the TextToSpeech engine can be cleanly stopped. - * - * @see android.app.Activity#onDestroy() - */ - @Override - public void onDestroy() { - super.onDestroy(); - textToSpeech.shutdown(); - } - - /** - * Speaks the string using the specified queuing strategy and speech - * parameters. - */ - private void convertTextToSpeech(String text) { - - float speechRate = getProgressValue(mSb_SpeechRate.getProgress()); - textToSpeech.setSpeechRate(speechRate); - textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null); - - } - - @Override - public void onInit(int status) { - if (status == TextToSpeech.SUCCESS) { - int result = textToSpeech.setLanguage(Locale.US); - if (result == TextToSpeech.LANG_MISSING_DATA - || result == TextToSpeech.LANG_NOT_SUPPORTED) { - Log.e("error", "This Language is not supported"); - } - } else { - Log.e("error", "Initilization Failed!"); - } - } - - private void submit() { - String input = mEt_Spelling.getText().toString().trim(); - if (input.length() == 0) { - Toast.makeText(getActivity(), "Please enter the spelling", - Toast.LENGTH_SHORT).show(); - - } else { - mAlert.dismiss(); - boolean isCorrect = false; - if (mEt_Spelling.getText().toString().trim() - .equalsIgnoreCase(mWordList.get(count).getWord())) { - isCorrect = true; - mManager.incrementCorrect(); - } else { - mManager.incrementWrong(); - } - - 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 speechRate = temp * 2; - - if (speechRate < MIN_SPEECH_RATE) - speechRate = MIN_SPEECH_RATE; - return speechRate; - } - - -} 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 deleted file mode 100644 index a2856251..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/SpellingMainFragment.java +++ /dev/null @@ -1,85 +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.learnspelling; - -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; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.constant.Constants; - -/** - * @brief Simulator code for Learn Spelling Template - */ -public class SpellingMainFragment extends Fragment { - - public static Fragment newInstance(String path) { - SpellingMainFragment fragment = new SpellingMainFragment(); - Bundle bundle = new Bundle(); - bundle.putString(Constants.SIMULATOR_FILE_PATH, path); - fragment.setArguments(bundle); - return fragment; - } - - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - View view = inflater.inflate(R.layout.spelling_fragment_main, container, false); - 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().getSupportFragmentManager().beginTransaction().replace(R.id.container, new SpellingActivity()).addToBackStack(null).commit(); - } - }); - - DataManager mManager = DataManager.getInstance(); - mManager.reset(); - mManager.readXml(getArguments().getString(Constants.SIMULATOR_FILE_PATH)); - mTv_Title.setText(mManager.getTitle()); - mTv_Author.setText(mManager.getAuthor()); - - return view; - } - - -} 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 deleted file mode 100644 index 5049dad9..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordInfoActivity.java +++ /dev/null @@ -1,145 +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.learnspelling; - -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; -import android.widget.Button; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; - -import java.util.ArrayList; -import java.util.Locale; - -/** - * @brief Simulator code for Learn Spelling Template - */ -public class WordInfoActivity extends Fragment { - - private boolean isCorrect; - private int position; - private DataManager mManager; - private ArrayList mList; - private TextToSpeech textToSpeech; - - public static Fragment newInstance(boolean isCorrect, int count, String word) { - Fragment fragment = new WordInfoActivity(); - Bundle bundle = new Bundle(); - bundle.putBoolean("result", isCorrect); - bundle.putInt("index", count); - bundle.putString("word", word); - - fragment.setArguments(bundle); - - return fragment; - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - 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); - 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"); - } - if (isCorrect) { - mTv_Result.setText(getString(R.string.msg_successful)); - mTv_Result.setTextColor(Color.GREEN); - mTv_enteredWord.setVisibility(View.GONE); - } else { - mTv_Result.setText(getString(R.string.msg_failure)); - mTv_Result.setTextColor(Color.RED); - mTv_enteredWord.setText(getString(R.string.you_entered) + " " - + enteredText.toLowerCase()); - } - textToSpeech = new TextToSpeech(getActivity(), - new TextToSpeech.OnInitListener() { - - @Override - public void onInit(int arg0) { - if (arg0 == TextToSpeech.SUCCESS) { - textToSpeech.setLanguage(Locale.US); - if (isCorrect) - convertTextToSpeech(getString(R.string.msg_successful)); - else - convertTextToSpeech(getString(R.string.msg_failure)); - } - } - }); - mTv_Word_num.setText("Word #" + (position + 1) + " of " + mList.size()); - mTv_word.setText(mList.get(position).getWord().toLowerCase()); - mTv_description.setText(mList.get(position).getDescription()); - - - view.findViewById(R.id.btn_next).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (position < mList.size() - 1) { - mManager.increaseCount(); - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new SpellingActivity()).addToBackStack(null).commit(); - } else { - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new ResultActivity()).addToBackStack(null).commit(); - } - } - }); - return view; - } - - - @Override - public void onDestroy() { - super.onDestroy(); - textToSpeech.shutdown(); - } - - private void convertTextToSpeech(String text) { - - textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null); - } -} 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 deleted file mode 100644 index 6d677370..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/WordModel.java +++ /dev/null @@ -1,65 +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.learnspelling; - -/** - * @brief Simulator code for Learn Spelling Template - */ -class WordModel { - - private String mWord; - private String mDescription; - - public WordModel() { - - } - - public WordModel(String word, String description) { - mWord = word; - mDescription = description; - - } - - public String getWord() { - return mWord; - } - - public void setWord(String mWord) { - this.mWord = mWord; - } - - public String getDescription() { - return mDescription; - } - - public void setDescription(String mDescription) { - this.mDescription = mDescription; - } - -} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/DataUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/DataUtils.java new file mode 100644 index 00000000..0f01555b --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/DataUtils.java @@ -0,0 +1,48 @@ +package org.buildmlearn.toolkit.learnspelling.data; + +import org.buildmlearn.toolkit.learnspelling.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 31/5/16. + */ + +/** + * @brief Contains xml data utils for learnspelling template's simulator. + */ +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/learnspelling/data/FetchXMLTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/FetchXMLTask.java new file mode 100644 index 00000000..982ef2c5 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/FetchXMLTask.java @@ -0,0 +1,137 @@ +package org.buildmlearn.toolkit.learnspelling.data; + +import android.content.ContentValues; +import android.content.Context; +import android.os.AsyncTask; + +import org.buildmlearn.toolkit.learnspelling.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 11/6/16. + */ + +/** + * @brief Used to parse XML and save in database for learn spelling template's simulator. + */ +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 saveSpellData(ArrayList Spells) { + + Vector cVVector = new Vector<>(Spells.size()); + + for (int i = 0; i < Spells.size(); i++) { + + String word; + String meaning; + + SpellModel SpellSpell = Spells.get(i); + + word = SpellSpell.getWord(); + meaning = SpellSpell.getMeaning(); + + ContentValues SpellValues = new ContentValues(); + + SpellValues.put(SpellContract.Spellings.WORD, word); + SpellValues.put(SpellContract.Spellings.MEANING, meaning); + SpellValues.put(SpellContract.Spellings.ATTEMPTED, 0); + + cVVector.add(SpellValues); + } + // add to database + if (cVVector.size() > 0) { + ContentValues[] cvArray = new ContentValues[cVVector.size()]; + cVVector.toArray(cvArray); + SpellDb db = new SpellDb(mContext); + db.open(); + db.bulkInsertSpellings(cvArray); + db.close(); + } + } + + @Override + protected Void doInBackground(String... params) { + + if (params.length == 0) { + return null; + } + String fileName = params[0]; + 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++) { + SpellModel app = new SpellModel(); + + Node child = childNodes.item(i); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element2 = (Element) child; + + app.setWord(getValue("word", element2)); + app.setMeaning(getValue("meaning", element2)); + + } + mList.add(app); + } + saveSpellData(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/learnspelling/data/SpellContract.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellContract.java new file mode 100644 index 00000000..aab69e32 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellContract.java @@ -0,0 +1,23 @@ +package org.buildmlearn.toolkit.learnspelling.data; + +import android.provider.BaseColumns; + +/** + * Created by Anupam (opticod) on 1/6/16. + */ + +/** + * @brief Contains database contracts for spell template's simulator. + */ +class SpellContract { + + public static final class Spellings implements BaseColumns { + + public static final String TABLE_NAME = "spellings"; + + public static final String WORD = "word"; + public static final String MEANING = "meaning"; + public static final String ANSWERED = "answered"; + public static final String ATTEMPTED = "attempted"; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellDBHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellDBHelper.java new file mode 100644 index 00000000..d96d5bd4 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellDBHelper.java @@ -0,0 +1,43 @@ +package org.buildmlearn.toolkit.learnspelling.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.buildmlearn.toolkit.learnspelling.data.SpellContract.Spellings; + +/** + * Created by Anupam (opticod) on 1/6/16. + */ + +/** + * @brief DatabaseHelper for spell template's simulator. + */ +class SpellDBHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "learn_spell.db"; + private static final int DATABASE_VERSION = 1; + + public SpellDBHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + final String SQL_CREATE__TABLE_A = "CREATE TABLE " + Spellings.TABLE_NAME + " (" + + Spellings._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Spellings.WORD + " TEXT," + + Spellings.MEANING + " TEXT," + + Spellings.ANSWERED + " INTEGER," + + Spellings.ATTEMPTED + " INTEGER )"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE_A); + + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Spellings.TABLE_NAME); + onCreate(sqLiteDatabase); + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellDb.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellDb.java new file mode 100644 index 00000000..70da4687 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellDb.java @@ -0,0 +1,138 @@ +package org.buildmlearn.toolkit.learnspelling.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.learnspelling.Constants; +import org.buildmlearn.toolkit.learnspelling.data.SpellContract.Spellings; + +import java.util.Arrays; + +/** + * Created by Anupam (opticod) on 1/6/16. + */ + +/** + * @brief Contains database util functions for spell template's simulator. + */ +public class SpellDb { + + private static final String EQUAL = " == "; + private final SpellDBHelper dbHelper; + private SQLiteDatabase db; + + public SpellDb(Context context) { + dbHelper = new SpellDBHelper(context); + } + + public void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public void close() { + dbHelper.close(); + } + + public void markAnswered(int id, String answer) { + + ContentValues values = new ContentValues(); + values.put(Spellings.ANSWERED, answer); + values.put(Spellings.ATTEMPTED, 1); + + db.update(Spellings.TABLE_NAME, values, Spellings._ID + " = ?", + new String[]{String.valueOf(id)}); + + } + + private void markUnAnswered(int id) { + + ContentValues values = new ContentValues(); + values.put(Spellings.ANSWERED, ""); + values.put(Spellings.ATTEMPTED, 0); + + db.update(Spellings.TABLE_NAME, values, Spellings._ID + " = ?", + new String[]{String.valueOf(id)}); + + } + + public void resetCount() { + for (int i = 1; i <= getCountSpellings(); i++) { + markUnAnswered(i); + } + } + + public int[] getStatistics() { + int stat[] = new int[3]; + Arrays.fill(stat, 0); + + for (int i = 1; i <= getCountSpellings(); i++) { + Cursor cursor = getSpellingCursorById(i); + cursor.moveToFirst(); + + String correct_answer = cursor.getString(Constants.COL_WORD); + int attempted = cursor.getInt(Constants.COL_ATTEMPTED); + if (attempted == 1) { + String answer = cursor.getString(Constants.COL_ANSWERED); + if (answer.equalsIgnoreCase(correct_answer)) { + stat[0]++; + } else { + stat[1]++; + } + } else { + stat[2]++; + } + } + return stat; + } + + public Cursor getSpellingCursorById(int id) { + + String selection = Spellings._ID + EQUAL + id; + + return db.query( + Spellings.TABLE_NAME, + null, + selection, + null, + null, + null, + null + ); + } + + public long getCountSpellings() { + + return DatabaseUtils.queryNumEntries(db, + Spellings.TABLE_NAME); + } + + public void deleteAll() { + db.delete(SpellContract.Spellings.TABLE_NAME, null, null); + db.execSQL("delete from sqlite_sequence where name='" + SpellContract.Spellings.TABLE_NAME + "';"); + } + + public int bulkInsertSpellings(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(Spellings.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/learnspelling/data/SpellModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellModel.java new file mode 100644 index 00000000..ba3f54f8 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/data/SpellModel.java @@ -0,0 +1,65 @@ +package org.buildmlearn.toolkit.learnspelling.data; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Created by Anupam (opticod) on 1/6/16. + */ + +/** + * @brief Model used to save spell entries in database for spell template's simulator. + */ +public class SpellModel implements Parcelable { + public final static Creator CREATOR = new Creator() { + @Override + public SpellModel createFromParcel(Parcel parcel) { + return new SpellModel(parcel); + } + + @Override + public SpellModel[] newArray(int size) { + return new SpellModel[size]; + } + }; + + private String word; + private String meaning; + + private SpellModel(Parcel in) { + this.word = in.readString(); + this.meaning = in.readString(); + } + + public SpellModel() { + + } + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + public String getMeaning() { + return meaning; + } + + public void setMeaning(String meaning) { + this.meaning = meaning; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(word); + dest.writeString(meaning); + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/LastFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/LastFragment.java new file mode 100644 index 00000000..6d4445c2 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/LastFragment.java @@ -0,0 +1,118 @@ +package org.buildmlearn.toolkit.learnspelling.fragment; + +import android.app.Activity; +import android.app.FragmentManager; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +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.learnspelling.data.SpellDb; + +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 2/6/16. + */ + +/** + * @brief Fragment for displaying score to user in learnspelling template's simulator. + */ +public class LastFragment extends Fragment { + + private SpellDb db; + + public static Fragment newInstance() { + return new LastFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_last_spell, container, false); + + final Activity activity = getActivity(); + + Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + toolbar.setTitle(getResources().getString(R.string.main_title_spell)); + 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; + 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; + } + }); + db = new SpellDb(activity); + db.open(); + + int stat[] = db.getStatistics(); + + assert rootView.findViewById(R.id.correct) != null; + ((TextView) rootView.findViewById(R.id.correct)).setText(String.format(Locale.getDefault(), "Total Correct : %1$d", stat[0])); + assert rootView.findViewById(R.id.wrong) != null; + ((TextView) rootView.findViewById(R.id.wrong)).setText(String.format(Locale.getDefault(), "Total Wrong : %1$d", stat[1])); + assert rootView.findViewById(R.id.un_answered) != null; + ((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(); + + db.resetCount(); + } + }); + + rootView.findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().finish(); + } + }); + + return rootView; + } + + @Override + public void onDestroy() { + db.close(); + super.onDestroy(); + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/MainFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/MainFragment.java new file mode 100644 index 00000000..1be0888a --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/MainFragment.java @@ -0,0 +1,360 @@ +package org.buildmlearn.toolkit.learnspelling.fragment; + +import android.app.FragmentManager; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.os.Build; +import android.os.Bundle; +import android.speech.tts.TextToSpeech; +import android.speech.tts.UtteranceProgressListener; +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.Button; +import android.widget.EditText; +import android.widget.SeekBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.learnspelling.Constants; +import org.buildmlearn.toolkit.learnspelling.data.SpellDb; + +import java.util.HashMap; +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 31/5/16. + */ + +/** + * @brief Fragment for the users to test their spelling skills. spelling template's simulator. + */ + +public class MainFragment extends Fragment + implements NavigationView.OnNavigationItemSelectedListener { + + private static final float MIN_SPEECH_RATE = 0.01f; + private android.app.AlertDialog mAlert; + private Context mContext; + private Button mBtn_Spell, mBtn_Skip; + private EditText mEt_Spelling; + private SeekBar mSb_SpeechRate; + private SpellDb db; + private TextToSpeech tts; + private ProgressDialog progress; + private View rootView; + + + public static Fragment newInstance() { + return new MainFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + rootView = inflater.inflate(R.layout.fragment_main_spell, 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.setTitle(getResources().getString(R.string.main_title_spell)); + + 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; + 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; + } + }); + + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( + getActivity(), drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); + assert drawer != null; + drawer.addDrawerListener(toggle); + toggle.syncState(); + + NavigationView navigationView = (NavigationView) rootView.findViewById(R.id.nav_view); + assert navigationView != null; + navigationView.setNavigationItemSelectedListener(this); + + mContext = getActivity(); + + db = new SpellDb(mContext); + db.open(); + + Bundle extras = getArguments(); + String spellId = "1"; + if (extras != null) { + spellId = extras.getString(Intent.EXTRA_TEXT); + } + + Menu m = navigationView.getMenu(); + SubMenu topChannelMenu = m.addSubMenu("Spellings"); + long numQues = db.getCountSpellings(); + + for (int i = 1; i <= numQues; i++) { + topChannelMenu.add(String.format(Locale.getDefault(), "Spelling %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)); + + 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(); + + return false; + } + }); + } + + MenuItem mi = m.getItem(m.size() - 1); + mi.setTitle(mi.getTitle()); + + + mBtn_Spell = (Button) rootView.findViewById(R.id.spell_it); + mBtn_Skip = (Button) rootView.findViewById(R.id.skip); + mSb_SpeechRate = (SeekBar) rootView.findViewById(R.id.seek_bar); + TextView mTv_WordNumber = (TextView) rootView.findViewById(R.id.intro_number); + + mBtn_Spell.setEnabled(false); + mBtn_Skip.setEnabled(false); + mTv_WordNumber.setText(String.format(Locale.ENGLISH, "Word #%d of %d", Integer.parseInt(spellId), numQues)); + + Cursor spell_cursor = db.getSpellingCursorById(Integer.parseInt(spellId)); + spell_cursor.moveToFirst(); + String word = spell_cursor.getString(Constants.COL_WORD); + String meaning = spell_cursor.getString(Constants.COL_MEANING); + String answered = spell_cursor.getString(Constants.COL_ANSWERED); + + setListeners(spellId, word, answered); + + return rootView; + } + + private void setListeners(final String spellId, final String word, final String answered) { + + rootView.findViewById(R.id.skip).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + long numColumns = db.getCountSpellings(); + + long nextSpellId = Integer.parseInt(spellId) + 1; + + if (nextSpellId <= numColumns) { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(nextSpellId)); + + 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(); + + } else { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(nextSpellId)); + + Fragment frag = LastFragment.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.speak_ico).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + progress = new ProgressDialog(mContext); + progress.setCancelable(false); + progress.setMessage("Loading TTS Engine..."); + progress.show(); + + + float speechRate = getProgressValue(mSb_SpeechRate.getProgress()); + tts.setSpeechRate(speechRate); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + String utteranceId = word.hashCode() + ""; + tts.speak(word, TextToSpeech.QUEUE_FLUSH, null, utteranceId); + } else { + HashMap map = new HashMap<>(); + map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "dict"); + tts.speak(word, TextToSpeech.QUEUE_FLUSH, map); + } + mBtn_Spell.setEnabled(true); + mBtn_Skip.setEnabled(true); + mBtn_Skip.setTextColor(ContextCompat.getColor(mContext, R.color.colorAccent_spell)); + mBtn_Spell.setTextColor(ContextCompat.getColor(mContext, R.color.colorAccent_spell)); + } + }); + + rootView.findViewById(R.id.spell_it).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + LayoutInflater factory = LayoutInflater.from(mContext); + final View textEntryView = factory.inflate( + R.layout.spelling_dialog_spellinginput, null); + android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(mContext); + mAlert = builder.create(); + mAlert.setCancelable(true); + mAlert.setView(textEntryView, 10, 10, 10, 10); + if (mAlert != null && !mAlert.isShowing()) { + mAlert.show(); + } + mEt_Spelling = (EditText) mAlert.findViewById(R.id.et_spelling); + mEt_Spelling.setText(answered); + + Button mBtn_Submit = (Button) mAlert.findViewById(R.id.btn_submit); + mBtn_Submit.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + submit(spellId); + } + }); + } + }); + + } + + private void submit(String spell) { + String input = mEt_Spelling.getText().toString().trim(); + if (input.length() == 0) { + Toast.makeText(mContext, "Please enter the spelling", + Toast.LENGTH_SHORT).show(); + + } else { + mAlert.dismiss(); + + String answered = mEt_Spelling.getText().toString().trim(); + db.markAnswered(Integer.parseInt(spell), answered); + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(spell)); + + Fragment frag = ResponseFragment.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(); + + } + } + + @Override + public void onDestroy() { + db.close(); + super.onDestroy(); + } + + @Override + public boolean onNavigationItemSelected(MenuItem item) { + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + assert drawer != null; + drawer.closeDrawer(GravityCompat.START); + return true; + } + + @Override + public void onPause() { + if (tts != null) { + tts.stop(); + tts.shutdown(); + } + super.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + tts = new TextToSpeech(mContext, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + int result = tts.setLanguage(Locale.US); + if (result == TextToSpeech.LANG_MISSING_DATA + || result == TextToSpeech.LANG_NOT_SUPPORTED) { + Toast.makeText(mContext, "US English is not supported. Playing in device's default installed language.", Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(mContext, "Initialization Failed!", Toast.LENGTH_SHORT).show(); + } + } + }); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { + tts.setOnUtteranceProgressListener(new UtteranceProgressListener() { + @Override + public void onStart(String utteranceId) { + progress.dismiss(); + } + + @Override + public void onDone(String utteranceId) { + + } + + @Override + public void onError(String utteranceId) { + + } + }); + } + } + + private float getProgressValue(int percent) { + float temp = ((float) percent / 100); + float speechRate = temp * 2; + + if (speechRate < MIN_SPEECH_RATE) + speechRate = MIN_SPEECH_RATE; + return speechRate; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/ResponseFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/ResponseFragment.java new file mode 100644 index 00000000..7f6b5b6d --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/ResponseFragment.java @@ -0,0 +1,215 @@ +package org.buildmlearn.toolkit.learnspelling.fragment; + +import android.app.FragmentManager; +import android.content.Context; +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.Html; +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.learnspelling.Constants; +import org.buildmlearn.toolkit.learnspelling.data.SpellDb; + +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 31/5/16. + */ + +/** + * @brief Fragment for displaying the correct and user entered spell to users in spelling template's simulator. + */ + +public class ResponseFragment extends Fragment + implements NavigationView.OnNavigationItemSelectedListener { + + private SpellDb db; + private View rootView; + + public static Fragment newInstance() { + return new ResponseFragment(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + rootView = inflater.inflate(R.layout.fragment_response_spell, 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.setTitle(getResources().getString(R.string.main_title_spell)); + + 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; + 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; + } + }); + + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( + getActivity(), drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); + assert drawer != null; + drawer.addDrawerListener(toggle); + toggle.syncState(); + + NavigationView navigationView = (NavigationView) rootView.findViewById(R.id.nav_view); + assert navigationView != null; + navigationView.setNavigationItemSelectedListener(this); + + Context mContext = getActivity(); + + db = new SpellDb(mContext); + db.open(); + + + Bundle extras = getArguments(); + String spellId = "1"; + if (extras != null) { + spellId = extras.getString(Intent.EXTRA_TEXT); + } + + Cursor spell_cursor = db.getSpellingCursorById(Integer.parseInt(spellId)); + spell_cursor.moveToFirst(); + String word = spell_cursor.getString(Constants.COL_WORD); + String meaning = spell_cursor.getString(Constants.COL_MEANING); + String answered = spell_cursor.getString(Constants.COL_ANSWERED); + + + Menu m = navigationView.getMenu(); + SubMenu topChannelMenu = m.addSubMenu("Spellings"); + long numQues = db.getCountSpellings(); + + for (int i = 1; i <= numQues; i++) { + topChannelMenu.add(String.format(Locale.getDefault(), "Spelling %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)); + + 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(); + + return false; + } + }); + } + + MenuItem mi = m.getItem(m.size() - 1); + mi.setTitle(mi.getTitle()); + + TextView mTv_WordNumber = (TextView) rootView.findViewById(R.id.intro_number); + + mTv_WordNumber.setText(String.format(Locale.ENGLISH, "Word #%d of %d", Integer.parseInt(spellId), numQues)); + + String message; + String word_text_view; + if (word.trim().equalsIgnoreCase(answered)) { + message = "Great! You got it right."; + word_text_view = "Correct Spell:  " + word + ""; + } else { + message = "Oops! You got it wrong."; + word_text_view = "Correct Spell:  " + word + "
You entered:  " + answered + ""; + } + + assert rootView.findViewById(R.id.intro_response) != null; + ((TextView) rootView.findViewById(R.id.intro_response)).setText(message); + assert rootView.findViewById(R.id.word) != null; + ((TextView) rootView.findViewById(R.id.word)).setText(Html.fromHtml(word_text_view), TextView.BufferType.SPANNABLE); + + assert rootView.findViewById(R.id.meaning) != null; + ((TextView) rootView.findViewById(R.id.meaning)).setText(meaning); + + final String finalSpellId = spellId; + rootView.findViewById(R.id.next).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + long numColumns = db.getCountSpellings(); + + long nextSpellId = Integer.parseInt(finalSpellId) + 1; + + if (nextSpellId <= numColumns) { + + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(nextSpellId)); + + 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(); + + } else { + Bundle arguments = new Bundle(); + arguments.putString(Intent.EXTRA_TEXT, String.valueOf(nextSpellId)); + + Fragment frag = LastFragment.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 onDestroy() { + db.close(); + super.onDestroy(); + } + + @Override + public boolean onNavigationItemSelected(MenuItem item) { + DrawerLayout drawer = (DrawerLayout) rootView.findViewById(R.id.drawer_layout); + assert drawer != null; + drawer.closeDrawer(GravityCompat.START); + return true; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/SplashFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/SplashFragment.java new file mode 100644 index 00000000..2bc27c62 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/learnspelling/fragment/SplashFragment.java @@ -0,0 +1,68 @@ +package org.buildmlearn.toolkit.learnspelling.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.learnspelling.Constants; +import org.buildmlearn.toolkit.learnspelling.data.DataUtils; +import org.buildmlearn.toolkit.learnspelling.data.FetchXMLTask; +import org.buildmlearn.toolkit.learnspelling.data.SpellDb; +import org.buildmlearn.toolkit.views.TextViewPlus; + +/** + * Created by Anupam (opticod) on 6/7/16. + */ + +/** + * @brief Splash intro Fragment for spelling template's simulator. + */ +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_spell)); + + 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(); + } + }); + + SpellDb db = new SpellDb(mActivity); + db.open(); + db.deleteAll(); + + long numColumns = db.getCountSpellings(); + 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/matchtemplate/Constants.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/Constants.java new file mode 100644 index 00000000..97be5c19 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/Constants.java @@ -0,0 +1,19 @@ +package org.buildmlearn.toolkit.matchtemplate; + +/** + * Created by Anupam (opticod) on 24/7/16. + */ + +/** + * @brief Constants used in match template's simulator relating databases. + */ +public class Constants { + public static final int COL_TITLE_META = 1; + public static final int COL_FIRST_TITLE = 2; + public static final int COL_SECOND_TITLE = 3; + public static final int COL_MATCH_A = 1; + public static final int COL_MATCH_B = 2; + public static final String first_list = "firstList"; + public static final String second_list = "secondList"; + public static String XMLFileName = "match_content.xml"; +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/adapter/MatchArrayAdapter_A.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/adapter/MatchArrayAdapter_A.java new file mode 100644 index 00000000..eb35cab5 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/adapter/MatchArrayAdapter_A.java @@ -0,0 +1,59 @@ +package org.buildmlearn.toolkit.matchtemplate.adapter; + +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.ArrayAdapter; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.matchtemplate.data.MatchModel; + +import java.util.ArrayList; + +/** + * Created by Anupam (opticod) on 24/7/16. + */ + +/** + * @brief Custom Adapter for match template's simulator. + */ +public class MatchArrayAdapter_A extends ArrayAdapter { + + public MatchArrayAdapter_A(Context context, ArrayList lists) { + super(context, 0, lists); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + MatchModel match = getItem(position); + + ViewHolder viewHolder; + + if (convertView == null) { + viewHolder = new ViewHolder(); + LayoutInflater inflater = LayoutInflater.from(getContext()); + convertView = inflater.inflate(R.layout.match_template_list_item_info, parent, false); + viewHolder.text = (TextView) convertView.findViewById(R.id.text); + convertView.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + viewHolder.text.setText(match.getMatchA()); + if (match.getCorrect() == 2) { + convertView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.item_correct_match)); + } else if (match.getCorrect() == 1) { + convertView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.item_wrong_match)); + } + + return convertView; + } + + public static class ViewHolder { + + public TextView text; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/adapter/MatchArrayAdapter_B.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/adapter/MatchArrayAdapter_B.java new file mode 100644 index 00000000..b2908eb9 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/adapter/MatchArrayAdapter_B.java @@ -0,0 +1,59 @@ +package org.buildmlearn.toolkit.matchtemplate.adapter; + +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.ArrayAdapter; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.matchtemplate.data.MatchModel; + +import java.util.ArrayList; + +/** + * Created by Anupam (opticod) on 24/7/16. + */ + +/** + * @brief Custom Adapter for match template's simulator. + */ +public class MatchArrayAdapter_B extends ArrayAdapter { + + public MatchArrayAdapter_B(Context context, ArrayList lists) { + super(context, 0, lists); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + MatchModel match = getItem(position); + + ViewHolder viewHolder; + + if (convertView == null) { + viewHolder = new ViewHolder(); + LayoutInflater inflater = LayoutInflater.from(getContext()); + convertView = inflater.inflate(R.layout.match_template_list_item_info, parent, false); + viewHolder.text = (TextView) convertView.findViewById(R.id.text); + convertView.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + viewHolder.text.setText(match.getMatchB()); + if (match.getCorrect() == 2) { + convertView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.item_correct_match)); + } else if (match.getCorrect() == 1) { + convertView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.item_wrong_match)); + } + + return convertView; + } + + public static class ViewHolder { + + public TextView text; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/DataUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/DataUtils.java new file mode 100644 index 00000000..3b15f3b2 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/DataUtils.java @@ -0,0 +1,49 @@ +package org.buildmlearn.toolkit.matchtemplate.data; + +import org.buildmlearn.toolkit.matchtemplate.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 24/7/16. + */ + +/** + * @brief Contains xml data utils for match template's simulator. + */ +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/matchtemplate/data/FetchXMLTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/FetchXMLTask.java new file mode 100644 index 00000000..214fafe3 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/FetchXMLTask.java @@ -0,0 +1,158 @@ +package org.buildmlearn.toolkit.matchtemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.os.AsyncTask; + +import org.buildmlearn.toolkit.matchtemplate.Constants; +import org.buildmlearn.toolkit.matchtemplate.data.MatchContract.Matches; +import org.buildmlearn.toolkit.matchtemplate.data.MatchContract.MetaDetails; +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 24/7/16. + */ + +/** + * @brief Used to parse XML and save in database for match template's simulator. + */ +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(MatchMetaModel metaDetails) { + + String title; + String first_list_title; + String second_list_title; + + title = metaDetails.getTitle(); + first_list_title = metaDetails.getFirstListTitle(); + second_list_title = metaDetails.getSecondListTitle(); + + ContentValues metaValues = new ContentValues(); + + metaValues.put(MetaDetails.TITLE, title); + metaValues.put(MetaDetails.FIRST_TITLE_TAG, first_list_title); + metaValues.put(MetaDetails.SECOND_TITLE_TAG, second_list_title); + + MatchDb db = new MatchDb(mContext); + db.open(); + db.bulkInsertMetaDetails(new ContentValues[]{metaValues}); + db.close(); + } + + private void saveMatches(ArrayList matches) { + + Vector cVVector = new Vector<>(matches.size()); + + for (int i = 0; i < matches.size(); i++) { + + MatchModel matchInfo = matches.get(i); + ContentValues matchValues = new ContentValues(); + + matchValues.put(Matches.MATCH_A, matchInfo.getMatchA()); + matchValues.put(Matches.MATCH_B, matchInfo.getMatchB()); + + cVVector.add(matchValues); + } + // add to database + if (cVVector.size() > 0) { + ContentValues[] cvArray = new ContentValues[cVVector.size()]; + cVVector.toArray(cvArray); + MatchDb db = new MatchDb(mContext); + db.open(); + db.bulkInsertMatches(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<>(); + + String match_title = doc.getElementsByTagName(MatchMetaModel.TITLE_TAG).item(0).getTextContent(); + String first_list_title = doc.getElementsByTagName(MatchMetaModel.FIRST_TITLE_TAG).item(0).getTextContent(); + String second_list_title = doc.getElementsByTagName(MatchMetaModel.SECOND_TITLE_TAG).item(0).getTextContent(); + + saveMetaData(new MatchMetaModel(match_title, first_list_title, second_list_title)); + + NodeList childNodes = doc.getElementsByTagName("item"); + + for (int i = 0; i < childNodes.getLength(); i++) { + MatchModel app = new MatchModel(); + + Node child = childNodes.item(i); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element2 = (Element) child; + + app.setMatchA(getValue("first_list_item", element2)); + app.setMatchB(getValue("second_list_item", element2)); + } + mList.add(app); + } + saveMatches(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/matchtemplate/data/MatchContract.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchContract.java new file mode 100644 index 00000000..0a3cec74 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchContract.java @@ -0,0 +1,32 @@ +package org.buildmlearn.toolkit.matchtemplate.data; + +import android.provider.BaseColumns; + +/** + * Created by Anupam (opticod) on 24/7/16. + */ + +/** + * @brief Contains database contracts for match template's simulator. + */ +class MatchContract { + + public static final class Matches implements BaseColumns { + + public static final String TABLE_NAME = "matches"; + + public static final String MATCH_A = "match_a"; + public static final String MATCH_B = "match_b"; + + } + + 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 FIRST_TITLE_TAG = "first_list_title"; + public static final String SECOND_TITLE_TAG = "second_list_title"; + + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchDBHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchDBHelper.java new file mode 100644 index 00000000..848b5b2f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchDBHelper.java @@ -0,0 +1,50 @@ +package org.buildmlearn.toolkit.matchtemplate.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.buildmlearn.toolkit.matchtemplate.data.MatchContract.Matches; +import org.buildmlearn.toolkit.matchtemplate.data.MatchContract.MetaDetails; + +/** + * Created by Anupam (opticod) on 24/7/16. + */ + +/** + * @brief DatabaseHelper for match template's simulator. + */ +class MatchDBHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "matches.db"; + private static final int DATABASE_VERSION = 1; + + public MatchDBHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + final String SQL_CREATE__TABLE_A = "CREATE TABLE " + Matches.TABLE_NAME + " (" + + Matches._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Matches.MATCH_A + " TEXT," + + Matches.MATCH_B + " TEXT)"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE_A); + + final String SQL_CREATE__TABLE_B = "CREATE TABLE " + MatchContract.MetaDetails.TABLE_NAME + " (" + + MatchContract.MetaDetails._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + MetaDetails.TITLE + " TEXT," + + MetaDetails.FIRST_TITLE_TAG + " TEXT," + + MetaDetails.SECOND_TITLE_TAG + " TEXT )"; + + sqLiteDatabase.execSQL(SQL_CREATE__TABLE_B); + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Matches.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/matchtemplate/data/MatchDb.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchDb.java new file mode 100644 index 00000000..526b1bae --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchDb.java @@ -0,0 +1,104 @@ +package org.buildmlearn.toolkit.matchtemplate.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 24/7/16. + */ + +/** + * @brief Contains database util functions for match template's simulator. + */ +public class MatchDb { + + private final MatchDBHelper dbHelper; + private SQLiteDatabase db; + + public MatchDb(Context context) { + dbHelper = new MatchDBHelper(context); + } + + public void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public void close() { + dbHelper.close(); + } + + public Cursor getMetaCursor() { + + return db.query( + MatchContract.MetaDetails.TABLE_NAME, + null, + null, + null, + null, + null, + null + ); + } + + public Cursor getRandMatchCursor() { + + return db.query(MatchContract.Matches.TABLE_NAME + " Order BY RANDOM() ", + new String[]{"*"}, null, null, null, null, null); + } + + public void deleteAll() { + db.delete(MatchContract.Matches.TABLE_NAME, null, null); + db.delete(MatchContract.MetaDetails.TABLE_NAME, null, null); + db.execSQL("delete from sqlite_sequence where name='" + MatchContract.Matches.TABLE_NAME + "';"); + db.execSQL("delete from sqlite_sequence where name='" + MatchContract.MetaDetails.TABLE_NAME + "';"); + } + + public int bulkInsertMatches(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(MatchContract.Matches.TABLE_NAME, null, value); + if (_id != -1) { + returnCount++; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + return returnCount; + } + + public long getCountMatches() { + + return DatabaseUtils.queryNumEntries(db, + MatchContract.Matches.TABLE_NAME); + } + + public int bulkInsertMetaDetails(@NonNull ContentValues[] values) { + + db.beginTransaction(); + int returnCount = 0; + try { + for (ContentValues value : values) { + + long _id = db.insert(MatchContract.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/matchtemplate/data/MatchMetaModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchMetaModel.java new file mode 100644 index 00000000..4bff8c44 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchMetaModel.java @@ -0,0 +1,70 @@ +package org.buildmlearn.toolkit.matchtemplate.data; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @brief Model class for Match The Following Meta Template Editor data + * Created by Anupam (opticod) on 24/7/16. + */ + +/** + * @brief Model used to save match meta entries in database for match template's simulator. + */ +public class MatchMetaModel implements Parcelable { + + public static final String TITLE_TAG = "meta_title"; + public static final String FIRST_TITLE_TAG = "meta_first_list_title"; + public static final String SECOND_TITLE_TAG = "meta_second_list_title"; + public final static Creator CREATOR = new Creator() { + @Override + public MatchMetaModel createFromParcel(Parcel parcel) { + return new MatchMetaModel(parcel); + } + + @Override + public MatchMetaModel[] newArray(int size) { + return new MatchMetaModel[size]; + } + }; + private final String title; + private final String first_list_title; + private final String second_list_title; + + public MatchMetaModel(String t, String A, String B) { + this.title = t; + this.first_list_title = A; + this.second_list_title = B; + } + + private MatchMetaModel(Parcel in) { + this.title = in.readString(); + this.first_list_title = in.readString(); + this.second_list_title = in.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(title); + dest.writeString(first_list_title); + dest.writeString(second_list_title); + } + + public String getFirstListTitle() { + return first_list_title; + } + + public String getSecondListTitle() { + return second_list_title; + } + + public String getTitle() { + return title; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchModel.java new file mode 100644 index 00000000..f6e035cd --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/data/MatchModel.java @@ -0,0 +1,76 @@ +package org.buildmlearn.toolkit.matchtemplate.data; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @brief Model class for Match The Following Template Editor data + *

+ * Created by Anupam (opticod) on 24/7/16. + */ + +/** + * @brief Model used to save match entries in database for match template's simulator. + */ +public class MatchModel implements Parcelable { + public final static Creator CREATOR = new Creator() { + @Override + public MatchModel createFromParcel(Parcel parcel) { + return new MatchModel(parcel); + } + + @Override + public MatchModel[] newArray(int size) { + return new MatchModel[size]; + } + }; + + private String matchA; + private String matchB; + private int correct; + + public MatchModel() { + + } + + private MatchModel(Parcel in) { + this.matchA = in.readString(); + this.matchB = in.readString(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(matchA); + dest.writeString(matchB); + } + + public int getCorrect() { + return correct; + } + + public void setCorrect(int correct) { + this.correct = correct; + } + + @Override + public int describeContents() { + return 0; + } + + public String getMatchA() { + return matchA; + } + + public void setMatchA(String matchA) { + this.matchA = matchA; + } + + public String getMatchB() { + return matchB; + } + + public void setMatchB(String matchB) { + this.matchB = matchB; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/DetailFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/DetailFragment.java new file mode 100644 index 00000000..70310c3b --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/DetailFragment.java @@ -0,0 +1,236 @@ +package org.buildmlearn.toolkit.matchtemplate.fragment; + +import android.app.FragmentManager; +import android.database.Cursor; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +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.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.ListView; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.matchtemplate.Constants; +import org.buildmlearn.toolkit.matchtemplate.adapter.MatchArrayAdapter_A; +import org.buildmlearn.toolkit.matchtemplate.adapter.MatchArrayAdapter_B; +import org.buildmlearn.toolkit.matchtemplate.data.MatchDb; +import org.buildmlearn.toolkit.matchtemplate.data.MatchModel; + +import java.util.ArrayList; +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 26/7/16. + */ + +/** + * @brief Fragment for displaying score with matched results in match template's simulator. + */ +public class DetailFragment extends Fragment { + + private static final String SELECTED_KEY_A = "selected_position_a"; + private static final String SELECTED_KEY_B = "selected_position_b"; + + private int mPositionA = ListView.INVALID_POSITION; + private int mPositionB = ListView.INVALID_POSITION; + private ListView listViewA; + private ListView listViewB; + + private ArrayList matchListA; + private ArrayList matchListB; + private MatchDb db; + + public static Fragment newInstance() { + return new DetailFragment(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putParcelableArrayList("matchListA", matchListA); + outState.putParcelableArrayList("matchListB", matchListB); + if (mPositionA != ListView.INVALID_POSITION) { + outState.putInt(SELECTED_KEY_A, mPositionA); + } + if (mPositionB != ListView.INVALID_POSITION) { + outState.putInt(SELECTED_KEY_B, mPositionB); + } + super.onSaveInstanceState(outState); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState == null || !savedInstanceState.containsKey("matchListA") || !savedInstanceState.containsKey("matchListB")) { + matchListA = new ArrayList<>(); + matchListB = new ArrayList<>(); + } else { + matchListA = savedInstanceState.getParcelableArrayList("matchListA"); + matchListB = savedInstanceState.getParcelableArrayList("matchListB"); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + db = new MatchDb(getContext()); + db.open(); + + Bundle arguments = getArguments(); + if (arguments != null) { + matchListA = arguments.getParcelableArrayList(Constants.first_list); + matchListB = arguments.getParcelableArrayList(Constants.second_list); + } + + long countScore = 0; + for (int i = 0; i < matchListA.size(); i++) { + MatchModel matchA = matchListA.get(i); + MatchModel matchB = matchListB.get(i); + if (!matchA.getMatchA().equals(matchB.getMatchA())) { + matchA.setCorrect(1); + matchB.setCorrect(1); + } else { + countScore++; + matchA.setCorrect(2); + matchB.setCorrect(2); + } + } + + + MatchArrayAdapter_A matchListAdapterA = new MatchArrayAdapter_A( + getActivity(), matchListA); + + MatchArrayAdapter_B matchListAdapterB = new MatchArrayAdapter_B( + getActivity(), matchListB); + + View rootView = inflater.inflate(R.layout.match_template_main, container, false); + + Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + 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; + 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; + } + }); + + listViewA = (ListView) rootView.findViewById(R.id.list_view_match_A); + listViewB = (ListView) rootView.findViewById(R.id.list_view_match_B); + + ColorDrawable colDivider = new ColorDrawable(ContextCompat.getColor(getContext(), R.color.white_primary_text)); + listViewA.setDivider(colDivider); + listViewB.setDivider(colDivider); + + listViewA.setDividerHeight(2); + listViewB.setDividerHeight(2); + + handleListViewListeners(); + + listViewA.setAdapter(matchListAdapterA); + listViewB.setAdapter(matchListAdapterB); + + View header_A = getLayoutInflater(savedInstanceState).inflate(R.layout.match_template_detail_header_a, null); + View footer_A = getLayoutInflater(savedInstanceState).inflate(R.layout.match_template_detail_footer_a, null); + listViewA.addHeaderView(header_A); + listViewA.addFooterView(footer_A); + + View header_B = getLayoutInflater(savedInstanceState).inflate(R.layout.match_template_detail_header_b, null); + View footer_B = getLayoutInflater(savedInstanceState).inflate(R.layout.match_template_detail_footer_b, null); + listViewB.addHeaderView(header_B); + listViewB.addFooterView(footer_B); + + ((TextView) rootView.findViewById(R.id.score)).setText(String.format(Locale.ENGLISH, "Score : %d of %d", countScore, matchListA.size())); + + if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY_A) && savedInstanceState.containsKey(SELECTED_KEY_B)) { + mPositionA = savedInstanceState.getInt(SELECTED_KEY_A); + mPositionB = savedInstanceState.getInt(SELECTED_KEY_B); + } + + rootView.findViewById(R.id.try_again).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + Bundle arguments = new Bundle(); + arguments.putParcelableArrayList(Constants.first_list, matchListA); + arguments.putParcelableArrayList(Constants.second_list, matchListB); + + 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(); + } + }); + + Cursor meta = db.getMetaCursor(); + + meta.moveToFirst(); + toolbar.setTitle(meta.getString(Constants.COL_TITLE_META)); + ((TextView) rootView.findViewById(R.id.first_list_title)).setText(meta.getString(Constants.COL_FIRST_TITLE)); + ((TextView) rootView.findViewById(R.id.second_list_title)).setText(meta.getString(Constants.COL_SECOND_TITLE)); + + return rootView; + } + + private void handleListViewListeners() { + + listViewA.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + + return false; + } + }); + + listViewB.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + //Left empty + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + View v = view.getChildAt(0); + if (v != null) + listViewA.setSelectionFromTop(firstVisibleItem, v.getTop()); + } + }); + + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + db.close(); + ViewGroup mContainer = (ViewGroup) getActivity().findViewById(R.id.container); + mContainer.removeAllViews(); + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/MainFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/MainFragment.java new file mode 100644 index 00000000..54f1b70f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/MainFragment.java @@ -0,0 +1,369 @@ +package org.buildmlearn.toolkit.matchtemplate.fragment; + +import android.app.FragmentManager; +import android.database.Cursor; +import android.graphics.Color; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.CardView; +import android.support.v7.widget.Toolbar; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.matchtemplate.Constants; +import org.buildmlearn.toolkit.matchtemplate.adapter.MatchArrayAdapter_A; +import org.buildmlearn.toolkit.matchtemplate.adapter.MatchArrayAdapter_B; +import org.buildmlearn.toolkit.matchtemplate.data.MatchDb; +import org.buildmlearn.toolkit.matchtemplate.data.MatchModel; + +import java.util.ArrayList; +import java.util.Collections; + +/** + * Created by Anupam (opticod) on 24/7/16. + */ + +/** + * @brief Fragment for the users to match column A with column B in match template's simulator. + */ +public class MainFragment extends Fragment { + + private static final String SELECTED_KEY_A = "selected_position_a"; + private static final String SELECTED_KEY_B = "selected_position_b"; + + private MatchArrayAdapter_A matchListAdapterA; + private MatchArrayAdapter_B matchListAdapterB; + private int mPositionA = ListView.INVALID_POSITION; + private int mPositionB = ListView.INVALID_POSITION; + private ListView listViewA; + private ListView listViewB; + + private ArrayList matchListA; + private ArrayList matchListB; + private MatchDb db; + + private int selectedPositionA = -1; + private int selectedPositionB = -1; + + private View selectedViewA; + private View selectedViewB; + private View clickSourceA; + + public static Fragment newInstance() { + return new MainFragment(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putParcelableArrayList("matchListA", matchListA); + outState.putParcelableArrayList("matchListB", matchListB); + if (mPositionA != ListView.INVALID_POSITION) { + outState.putInt(SELECTED_KEY_A, mPositionA); + } + if (mPositionB != ListView.INVALID_POSITION) { + outState.putInt(SELECTED_KEY_B, mPositionB); + } + super.onSaveInstanceState(outState); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState == null || !savedInstanceState.containsKey("matchListA") || !savedInstanceState.containsKey("matchListB")) { + matchListA = new ArrayList<>(); + matchListB = new ArrayList<>(); + } else { + matchListA = savedInstanceState.getParcelableArrayList("matchListA"); + matchListB = savedInstanceState.getParcelableArrayList("matchListB"); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + db = new MatchDb(getContext()); + db.open(); + + Cursor cursorMatchesA = db.getRandMatchCursor(); + Cursor cursorMatchesB = db.getRandMatchCursor(); + + Cursor meta = db.getMetaCursor(); + + if (cursorMatchesA != null) { + while (cursorMatchesA.moveToNext()) { + MatchModel match = new MatchModel(); + match.setMatchA(cursorMatchesA.getString(Constants.COL_MATCH_A)); + match.setMatchB(cursorMatchesA.getString(Constants.COL_MATCH_B)); + matchListA.add(match); + } + cursorMatchesA.close(); + } + + if (cursorMatchesB != null) { + while (cursorMatchesB.moveToNext()) { + MatchModel match = new MatchModel(); + match.setMatchA(cursorMatchesB.getString(Constants.COL_MATCH_A)); + match.setMatchB(cursorMatchesB.getString(Constants.COL_MATCH_B)); + matchListB.add(match); + } + cursorMatchesB.close(); + } + + matchListAdapterA = + new MatchArrayAdapter_A( + getActivity(), matchListA); + + matchListAdapterB = + new MatchArrayAdapter_B( + getActivity(), matchListB); + + View rootView = inflater.inflate(R.layout.match_template_main, container, false); + + Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + 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; + 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; + } + }); + + listViewA = (ListView) rootView.findViewById(R.id.list_view_match_A); + listViewB = (ListView) rootView.findViewById(R.id.list_view_match_B); + + handleListViewListeners(); + + listViewA.setAdapter(matchListAdapterA); + listViewB.setAdapter(matchListAdapterB); + + View header_A = getLayoutInflater(savedInstanceState).inflate(R.layout.match_template_main_header_a, null); + View footer_A = getLayoutInflater(savedInstanceState).inflate(R.layout.match_template_main_footer_a, null); + listViewA.addHeaderView(header_A); + listViewA.addFooterView(footer_A); + + View header_B = getLayoutInflater(savedInstanceState).inflate(R.layout.match_template_main_header_b, null); + View footer_B = getLayoutInflater(savedInstanceState).inflate(R.layout.match_template_main_footer_b, null); + listViewB.addHeaderView(header_B); + listViewB.addFooterView(footer_B); + + if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY_A) && savedInstanceState.containsKey(SELECTED_KEY_B)) { + mPositionA = savedInstanceState.getInt(SELECTED_KEY_A); + mPositionB = savedInstanceState.getInt(SELECTED_KEY_B); + } + + handleButtonListener(rootView); + + rootView.findViewById(R.id.check_answer).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + Bundle arguments = new Bundle(); + arguments.putParcelableArrayList(Constants.first_list, matchListA); + arguments.putParcelableArrayList(Constants.second_list, matchListB); + + Fragment frag = DetailFragment.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(); + } + }); + + meta.moveToFirst(); + toolbar.setTitle(meta.getString(Constants.COL_TITLE_META)); + ((TextView) rootView.findViewById(R.id.first_list_title)).setText(meta.getString(Constants.COL_FIRST_TITLE)); + ((TextView) rootView.findViewById(R.id.second_list_title)).setText(meta.getString(Constants.COL_SECOND_TITLE)); + + return rootView; + } + + private void handleListViewListeners() { + listViewA.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (parent == clickSourceA) { + highlightListA(position, view); + } + } + }); + + listViewB.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (parent != clickSourceA) { + highlightListB(position, view); + } + } + }); + + listViewA.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + clickSourceA = v; + } + return false; + } + }); + + listViewB.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + View v = view.getChildAt(0); + if (v != null) + listViewA.setSelectionFromTop(firstVisibleItem, v.getTop()); + } + }); + + } + + private void handleButtonListener(View rootView) { + rootView.findViewById(R.id.first_list_up).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selectedPositionA != -1 && selectedPositionA >= 1 && selectedPositionA < matchListA.size()) { + Collections.swap(matchListA, selectedPositionA, selectedPositionA - 1); + matchListAdapterA.notifyDataSetChanged(); + highlightListA(selectedPositionA, listViewA.getChildAt(selectedPositionA)); + } + } + }); + + rootView.findViewById(R.id.first_list_down).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selectedPositionA != -1 && selectedPositionA >= 0 && selectedPositionA <= matchListA.size() - 2) { + Collections.swap(matchListA, selectedPositionA, selectedPositionA + 1); + matchListAdapterA.notifyDataSetChanged(); + highlightListA(selectedPositionA + 2, listViewA.getChildAt(selectedPositionA + 2)); + } + } + }); + + rootView.findViewById(R.id.second_list_up).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selectedPositionB != -1 && selectedPositionB >= 1 && selectedPositionB < matchListB.size()) { + Collections.swap(matchListB, selectedPositionB, selectedPositionB - 1); + matchListAdapterB.notifyDataSetChanged(); + highlightListB(selectedPositionB, listViewB.getChildAt(selectedPositionB)); + } + } + }); + + rootView.findViewById(R.id.second_list_down).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selectedPositionB != -1 && selectedPositionB >= 0 && selectedPositionB <= matchListB.size() - 2) { + Collections.swap(matchListB, selectedPositionB, selectedPositionB + 1); + matchListAdapterB.notifyDataSetChanged(); + highlightListB(selectedPositionB + 2, listViewB.getChildAt(selectedPositionB + 2)); + } + } + }); + } + + private void highlightListA(int position, View view) { + if (position == 0) { + return; + } + + if (selectedPositionA == position - 1) { + selectedPositionA = -1; + if (view instanceof CardView) { + ((CardView) view).setCardBackgroundColor(Color.WHITE); + } else { + view.setBackgroundResource(0); + } + } else { + if (selectedViewA != null) { + if (selectedViewA instanceof CardView) { + ((CardView) selectedViewA).setCardBackgroundColor(Color.WHITE); + } else { + selectedViewA.setBackgroundResource(0); + } + } + selectedViewA = view; + selectedPositionA = position - 1; + if (view instanceof CardView) { + ((CardView) view).setCardBackgroundColor(Color.LTGRAY); + } else { + view.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.color_divider)); + } + } + } + + private void highlightListB(int position, View view) { + if (position == 0) { + return; + } + + if (selectedPositionB == position - 1) { + selectedPositionB = -1; + if (view instanceof CardView) { + ((CardView) view).setCardBackgroundColor(Color.WHITE); + } else { + view.setBackgroundResource(0); + } + } else { + if (selectedViewB != null) { + if (selectedViewB instanceof CardView) { + ((CardView) selectedViewB).setCardBackgroundColor(Color.WHITE); + } else { + selectedViewB.setBackgroundResource(0); + } + } + selectedViewB = view; + selectedPositionB = position - 1; + if (view instanceof CardView) { + ((CardView) view).setCardBackgroundColor(Color.LTGRAY); + } else { + view.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.color_divider)); + } + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + db.close(); + ViewGroup mContainer = (ViewGroup) getActivity().findViewById(R.id.container); + mContainer.removeAllViews(); + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/SplashFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/SplashFragment.java new file mode 100644 index 00000000..d797650b --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/matchtemplate/fragment/SplashFragment.java @@ -0,0 +1,69 @@ +package org.buildmlearn.toolkit.matchtemplate.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.matchtemplate.Constants; +import org.buildmlearn.toolkit.matchtemplate.data.DataUtils; +import org.buildmlearn.toolkit.matchtemplate.data.FetchXMLTask; +import org.buildmlearn.toolkit.matchtemplate.data.MatchDb; +import org.buildmlearn.toolkit.views.TextViewPlus; + +/** + * Created by Anupam (opticod) on 28/7/16. + */ + +/** + * @brief Splash intro Fragment for match template's simulator. + */ +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.match_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(); + } + }); + + MatchDb db = new MatchDb(mActivity); + db.open(); + db.deleteAll(); + + long numColumns = db.getCountMatches(); + 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/model/KeyStoreDetails.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/KeyStoreDetails.java index bd983e95..c9a569ca 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 @@ -12,8 +12,8 @@ public class KeyStoreDetails { private final String alias; private final String aliasPassword; - public KeyStoreDetails(String assetsPath, String password, String alias, String aliasPassword) { - this.assetsPath = assetsPath; + public KeyStoreDetails(String password, String alias, String aliasPassword) { + this.assetsPath = "TestKeyStore.jks"; this.password = password; this.alias = alias; this.aliasPassword = aliasPassword; diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/SavedApi.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/SavedApi.java index 1c3549fa..c23cc00e 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/model/SavedApi.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/model/SavedApi.java @@ -6,22 +6,21 @@ /** * Created by anupam on 29/2/16. */ -public class SavedApi { - private File file; +/** + * @brief Model used to hold api entries. + */ +public class SavedApi { + private final File file; + private final String date; private String name; - private String date; - private String type; private String author; - private String fullPath; public SavedApi(File file, String fileName, long date, String fullPath) { this.file = file; - this.fullPath = fullPath; this.date = formatDate(date); - this.type = type; String[] data = fileName.split("-by-"); try { this.name = data[0]; @@ -48,43 +47,16 @@ public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - public String getDate() { return date; } - public void setDate(long date) { - this.date = formatDate(date); - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - public String getAuthor() { return author; } - public void setAuthor(String author) { - this.author = author; - } - - public String getFullPath() { - return fullPath; - } - public File getFile() { return file; } - public void setFile(File file) { - this.file = file; - } } 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 dcefb4b7..e8d97744 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 @@ -5,9 +5,11 @@ import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.templates.ComprehensionTemplate; +import org.buildmlearn.toolkit.templates.DictationTemplate; import org.buildmlearn.toolkit.templates.FlashTemplate; import org.buildmlearn.toolkit.templates.InfoTemplate; import org.buildmlearn.toolkit.templates.LearnSpellingTemplate; +import org.buildmlearn.toolkit.templates.MatchTemplate; import org.buildmlearn.toolkit.templates.QuizTemplate; import org.buildmlearn.toolkit.templates.VideoCollectionTemplate; @@ -18,12 +20,14 @@ */ 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, R.string.info_assets_name), - LEARN_SPELLING(R.string.learn_spellings_title, R.string.learn_spellings_description, R.drawable.basic_m_learning, R.string.spelling_type, LearnSpellingTemplate.class, R.string.spelling_assets_name), - QUIZ(R.string.quiz_title, R.string.quiz_description, R.drawable.basic_m_learning, R.string.quiz_type, QuizTemplate.class, R.string.quiz_assets_name), - FLASH_CARD(R.string.flash_card_title, R.string.flash_card_description, R.drawable.basic_m_learning, R.string.flash_card_template, FlashTemplate.class, R.string.flash_assets_name), + 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, R.string.info_assets_name), + LEARN_SPELLING(R.string.learn_spellings_title, R.string.learn_spellings_description, R.drawable.spelling, R.string.spelling_type, LearnSpellingTemplate.class, R.string.spelling_assets_name), + QUIZ(R.string.quiz_title, R.string.quiz_description, R.drawable.quiz, R.string.quiz_type, QuizTemplate.class, R.string.quiz_assets_name), + FLASH_CARD(R.string.flash_card_title, R.string.flash_card_description, R.drawable.flash, R.string.flash_card_template, FlashTemplate.class, R.string.flash_assets_name), VIDEO_COLLECTION(R.string.video_collection_title, R.string.video_collection_description, R.drawable.video_collection, R.string.video_collection_template, VideoCollectionTemplate.class, R.string.video_assets_name), - COMPREHENSION(R.string.comprehension_title, R.string.comprehension_description, R.drawable.comprehension, R.string.comprehension_template, ComprehensionTemplate.class, R.string.comprehension_assets_name); + COMPREHENSION(R.string.comprehension_title, R.string.comprehension_description, R.drawable.comprehension, R.string.comprehension_template, ComprehensionTemplate.class, R.string.comprehension_assets_name), + DICTATION(R.string.dictation_title, R.string.dictation_description, R.drawable.dictation, R.string.dictation_template, DictationTemplate.class, R.string.dictation_assets_name), + MATCH_THE_FOLLOWING(R.string.match_title, R.string.match_description, R.drawable.match_template, R.string.match_template, MatchTemplate.class, R.string.match_assets_name); @StringRes final 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 1ec201aa..18674521 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 @@ -50,12 +50,6 @@ public interface TemplateInterface extends Serializable { BaseAdapter loadProjectTemplateEditor(Context context, ArrayList data); - /** - * @return Custom string - * @brief Called from TemplateEditor whenever a template is attached to TemplateEditor - */ - String onAttach(); - /** * @brief Set templateId,that can be used to get Info about current template from enum Template * @param templateId @@ -137,8 +131,4 @@ 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/quiztemplate/Constants.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/Constants.java new file mode 100644 index 00000000..c0c78041 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/Constants.java @@ -0,0 +1,22 @@ +package org.buildmlearn.toolkit.quiztemplate; + +/** + * Created by Anupam (opticod) on 14/8/16. + */ + +/** + * @brief Constants used in quiz template's simulator relating databases. + */ +public class Constants { + public static final String firstrun = "firstRun"; + 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 = "quiz_content.xml"; + +} 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 deleted file mode 100644 index 2b8551ce..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/GlobalData.java +++ /dev/null @@ -1,234 +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.quiztemplate; - -import android.content.Context; -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 org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -/** - * @brief Simulator code for Quiz Template - */ -public class GlobalData { - private static GlobalData instance = null; - final List iQuizList = new ArrayList<>(); - String iQuizTitle = null; - String iQuizAuthor = null; - ArrayList model = null; - int correct = 0; - int wrong = 0; - int total = 0; - int iSelectedIndex = -1; - private BufferedReader br; - - private 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 = nodeList.item(0); - - return node.getNodeValue(); - } - } - - public void ReadContent(Context myContext) { - try { - br = new BufferedReader(new InputStreamReader(myContext.getAssets() - .open("quiz_content.txt"))); // throwing a - // FileNotFoundException? - iQuizTitle = br.readLine(); - iQuizAuthor = br.readLine(); - String text; - while ((text = br.readLine()) != null) { - iQuizList.add(text); - } - total = iQuizList.size(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - br.close(); // stop reading - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - - public void readXmlContent(Context myContext, String fileName) { - XmlPullParserFactory factory; - XmlPullParser parser; - InputStreamReader is; - ArrayList mOptions = null; - try { - factory = XmlPullParserFactory.newInstance(); - // .setNamespaceAware(true); - factory.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); - - parser = factory.newPullParser(); - - is = new InputStreamReader(myContext.getAssets().open(fileName)); - - parser.setInput(is); - int eventType = parser.getEventType(); - QuestionModel app = null; - - while (eventType != XmlPullParser.END_DOCUMENT) { - String name; - switch (eventType) { - case XmlPullParser.START_DOCUMENT: - model = new ArrayList<>(); - break; - case XmlPullParser.START_TAG: - name = parser.getName(); - - if (name.equalsIgnoreCase("title")) { - iQuizTitle = parser.nextText(); - } else if (name.equalsIgnoreCase("author")) { - iQuizAuthor = parser.nextText(); - } else if (name.equalsIgnoreCase("item")) { - app = new QuestionModel(); - mOptions = new ArrayList<>(); - } else if (app != null) { - if (name.equalsIgnoreCase("question")) { - app.setQuestion(parser.nextText()); - } else if (name.equalsIgnoreCase("option")) { - mOptions.add(parser.nextText()); - app.setOptions(mOptions); - } else if (name.equalsIgnoreCase("answer")) { - app.setAnswer(parser.nextText()); - } - } - break; - case XmlPullParser.END_TAG: - name = parser.getName(); - if (name.equalsIgnoreCase("item") && app != null) { - model.add(app); - total = model.size(); - } - } - eventType = parser.next(); - - } - } catch (XmlPullParserException | IOException e1) { - e1.printStackTrace(); - } - // return model; - // BuildmLearnModel.getInstance(myContext).setAllAppsList(model); - - } - - public void readXml(String filePath) { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - - dbf.setValidating(false); - - ArrayList mOptions; - DocumentBuilder db; - Document doc; - try { - File fXmlFile = new File(filePath); - model = new ArrayList<>(); - db = dbf.newDocumentBuilder(); - doc = db.parse(fXmlFile); - doc.normalize(); - iQuizTitle = doc.getElementsByTagName("title").item(0) - .getChildNodes().item(0).getNodeValue(); - iQuizAuthor = doc.getElementsByTagName("name").item(0) - .getChildNodes().item(0).getNodeValue(); - NodeList childNodes = doc.getElementsByTagName("item"); - // Log.e("tag", "childNodes" + childNodes.getLength()); - for (int i = 0; i < childNodes.getLength(); i++) { - QuestionModel app = new QuestionModel(); - - 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.setAnswer(getValue("answer", element2)); - app.setOptions(mOptions); - } - model.add(app); - } - total = model.size(); - - } catch (ParserConfigurationException | IOException e) { - Log.e("tag", e.getLocalizedMessage()); - e.printStackTrace(); - } catch (SAXException 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/quiztemplate/QuestionFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionFragment.java deleted file mode 100644 index 5d20d2df..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionFragment.java +++ /dev/null @@ -1,193 +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.quiztemplate; - -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; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.RadioButton; -import android.widget.RadioGroup; -import android.widget.TextView; -import android.widget.Toast; - -import org.buildmlearn.toolkit.R; - -import java.util.ArrayList; -import java.util.List; - -/** - * @brief Simulator code for Quiz Template - */ -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 Button iSubmitButton; - private int iQuestionIndex = 0; - private int iCurrentCorrectAnswer; - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - 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); - - 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); - - RadioGroup iRadioGroup = (RadioGroup) view.findViewById(R.id.radioGroup1); - - iRadButtonList.add(iRad0); - iRadButtonList.add(iRad1); - iRadButtonList.add(iRad2); - iRadButtonList.add(iRad3); - - iSubmitButton = (Button) view.findViewById(R.id.submit_button); - iSubmitButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - int selectedAnswer = getSelectedAnswer(); - if (selectedAnswer == -1) { - Toast.makeText(getActivity(), - "Please select an answer!", Toast.LENGTH_LONG).show(); - } else if (selectedAnswer == iCurrentCorrectAnswer) { - iRadButtonList.get(iCurrentCorrectAnswer) - .setBackgroundColor(Color.GREEN); - Toast.makeText(getActivity(), - "That's the correct answer!", Toast.LENGTH_LONG).show(); - gd.correct++; - iSubmitButton.setEnabled(false); - - } else { - iRadButtonList.get(selectedAnswer).setBackgroundColor( - Color.RED); - iRadButtonList.get(iCurrentCorrectAnswer) - .setBackgroundColor(Color.GREEN); - Toast.makeText(getActivity(), - "Sorry, wrong answer!", Toast.LENGTH_LONG).show(); - - iSubmitButton.setEnabled(false); - gd.wrong++; - // iSubmitButton.setVisibility(View.GONE); - // iNextButton.setVisibility(View.VISIBLE); - - } - } - }); - - Button iNextButton = (Button) view.findViewById(R.id.next_button); - iNextButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - - // set all radios to white - for (int i = 0; i < iRadButtonList.size(); i++) { - iRadButtonList.get(i).setBackgroundColor(Color.TRANSPARENT); - } - - // Increase the index to next ques - iQuestionIndex = iQuestionIndex + 1; - - if (iQuestionIndex < gd.model.size()) { - populateQuestion(iQuestionIndex); - - iSubmitButton.setEnabled(true); - // iNextButton.setVisibility(View.GONE); - } else { - // if the quiz is over - reInitialize(); - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new ScoreFragment(), ScoreFragment.TAG).addToBackStack(null).commit(); - } - } - }); - // iNextButton.setVisibility(View.GONE); - - populateQuestion(iQuestionIndex); - - return view; - } - - - private void populateQuestion(int index) { - for (int i = 0; i < iRadButtonList.size(); i++) { - iRadButtonList.get(i).setBackgroundColor(Color.TRANSPARENT); - iRadButtonList.get(i).setChecked(false); - iRadButtonList.get(i).setVisibility(View.INVISIBLE); - } - - iQuestion_no_Label.setText("Question #" + String.valueOf(index + 1) - + " of " + gd.total); - iQuestionLabel.setText(gd.model.get(index).getQuestion()); - ArrayList options = gd.model.get(index).getOptions(); - for (int i = 0; i < options.size(); i++) { - iRadButtonList.get(i).setText(options.get(i)); - iRadButtonList.get(i).setVisibility(View.VISIBLE); - } - iCurrentCorrectAnswer = Integer - .parseInt(gd.model.get(index).getAnswer()); - - } - - private int getSelectedAnswer() { - int selected = -1; - for (int i = 0; i < iRadButtonList.size(); i++) { - if (iRadButtonList.get(i).isChecked()) { - return i; - } - } - return selected; - } - - private void reInitialize() { - - iQuestionIndex = 0; - gd.iQuizList.clear(); - } - -} \ No newline at end of file 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 deleted file mode 100644 index 60f24c1b..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/QuestionModel.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.buildmlearn.toolkit.quiztemplate; - -import java.util.ArrayList; - -/** - * @brief Simulator code for Quiz Template - */ -class QuestionModel { - - private String question, answer; - private ArrayList options; - - 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 String getAnswer() { - return answer; - } - - public void setAnswer(String answer) { - this.answer = answer; - } - - -} 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 deleted file mode 100644 index 8f67a8a7..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/ScoreFragment.java +++ /dev/null @@ -1,90 +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.quiztemplate; - -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; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.constant.Constants; - -/** - * @brief Simulator code for Quiz Template - */ -public class ScoreFragment extends Fragment { - - public final static String TAG = "SCORE_FRAGMENT"; - - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - FragmentActivity faActivity = super.getActivity(); - View view = inflater.inflate(R.layout.quiz_template_fragment_score_view, container, false); - - GlobalData gd = GlobalData.getInstance(); - - 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; - mTv_unanswered.setText("Unanswered: " + unanswered); - - Button startAgainButton = (Button) view.findViewById(R.id.start_again_button); - startAgainButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, TFTQuizFragment.newInstance(getActivity().getIntent().getStringExtra(Constants.SIMULATOR_FILE_PATH)), TFTQuizFragment.TAG).addToBackStack(null).commit(); - } - }); - - Button quitButton = (Button) view.findViewById(R.id.quit_button); - quitButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - getActivity().finish(); - } - }); - - return view; - } -} 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 deleted file mode 100644 index fb39acbb..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/TFTQuizFragment.java +++ /dev/null @@ -1,98 +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.quiztemplate; - -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; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.constant.Constants; - -/** - * @brief Simulator code for Quiz Template - */ -public class TFTQuizFragment extends Fragment { - - public final static String TAG = "QUIZ_FRAGMENT_START"; - - - private GlobalData gd; - - public static Fragment newInstance(String path) { - TFTQuizFragment fragment = new TFTQuizFragment(); - Bundle bundle = new Bundle(); - bundle.putString(Constants.SIMULATOR_FILE_PATH, path); - fragment.setArguments(bundle); - return fragment; - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - View view = inflater.inflate(R.layout.quiz_template_fragment_start_view, container, false); - - gd = GlobalData.getInstance(); - reInitialize(); - // gd.ReadContent(TFTQuizFragment.this); - gd.readXml(getArguments().getString(Constants.SIMULATOR_FILE_PATH)); - TextView quizAuthor = (TextView) view.findViewById(R.id.tv_author); - TextView quizTitle = (TextView) view.findViewById(R.id.tv_apptitle); - - quizAuthor.setText(gd.iQuizAuthor); - quizTitle.setText(gd.iQuizTitle); - - Button startButton = (Button) view.findViewById(R.id.btn_start); - startButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - - getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, new QuestionFragment(), QuestionFragment.TAG).addToBackStack(null).commit(); - } - }); - - return view; - } - - private void reInitialize() { - gd.total = 0; - gd.correct = 0; - gd.wrong = 0; - gd.iQuizList.clear(); - } - -} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/DataUtils.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/DataUtils.java new file mode 100644 index 00000000..6cbd836c --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/DataUtils.java @@ -0,0 +1,48 @@ +package org.buildmlearn.toolkit.quiztemplate.data; + +import org.buildmlearn.toolkit.quiztemplate.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 14/8/16. + */ + +/** + * @brief Contains xml data utils for quiz template's simulator. + */ +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/quiztemplate/data/FetchXMLTask.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/FetchXMLTask.java new file mode 100644 index 00000000..bd37d645 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/FetchXMLTask.java @@ -0,0 +1,160 @@ +package org.buildmlearn.toolkit.quiztemplate.data; + +import android.content.ContentValues; +import android.content.Context; +import android.os.AsyncTask; + +import org.buildmlearn.toolkit.quiztemplate.Constants; +import org.buildmlearn.toolkit.quiztemplate.data.QuizContract.Questions; +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 14/8/16. + */ + +/** + * @brief Used to parse XML and save in database for quiz template's simulator. + */ +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 saveQuestions(ArrayList questions) { + + Vector cVVector = new Vector<>(questions.size()); + + for (int i = 0; i < questions.size(); i++) { + + String question; + ArrayList options; + int correctAnswer; + + QuizModel 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); + QuizDb db = new QuizDb(mContext); + db.open(); + db.bulkInsertQuestions(cvArray); + db.close(); + } + } + + @Override + protected Void doInBackground(String... params) { + + if (params.length == 0) { + return null; + } + String fileName = params[0]; + 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<>(); + + NodeList childNodes = doc.getElementsByTagName("item"); + + for (int i = 0; i < childNodes.getLength(); i++) { + QuizModel app = new QuizModel(); + + 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/quiztemplate/data/QuizContract.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizContract.java new file mode 100644 index 00000000..e0cbee9f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizContract.java @@ -0,0 +1,28 @@ +package org.buildmlearn.toolkit.quiztemplate.data; + +import android.provider.BaseColumns; + +/** + * Created by Anupam (opticod) on 14/8/16. + */ + +/** + * @brief Contains database contracts for quiz template's simulator. + */ +class QuizContract { + + 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"; + + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizDBHelper.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizDBHelper.java new file mode 100644 index 00000000..2cb2ab92 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizDBHelper.java @@ -0,0 +1,46 @@ +package org.buildmlearn.toolkit.quiztemplate.data; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.buildmlearn.toolkit.quiztemplate.data.QuizContract.Questions; + +/** + * Created by Anupam (opticod) on 11/8/16. + */ + +/** + * @brief DatabaseHelper for quiz template's simulator. + */ +class QuizDBHelper extends SQLiteOpenHelper { + + private static final String DATABASE_NAME = "quiz.db"; + private static final int DATABASE_VERSION = 1; + + public QuizDBHelper(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); + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + Questions.TABLE_NAME); + onCreate(sqLiteDatabase); + } +} \ No newline at end of file diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizDb.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizDb.java new file mode 100644 index 00000000..33727b82 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizDb.java @@ -0,0 +1,138 @@ +package org.buildmlearn.toolkit.quiztemplate.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.quiztemplate.Constants; +import org.buildmlearn.toolkit.quiztemplate.data.QuizContract.Questions; + +import java.util.Arrays; + +/** + * Created by Anupam (opticod) on 14/8/16. + */ + +/** + * @brief Contains database util functions for quiz template's simulator. + */ +public class QuizDb { + + private static final String EQUAL = " == "; + private final QuizDBHelper dbHelper; + private SQLiteDatabase db; + + public QuizDb(Context context) { + dbHelper = new QuizDBHelper(context); + } + + public void open() throws SQLException { + db = dbHelper.getWritableDatabase(); + } + + public void close() { + dbHelper.close(); + } + + 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 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 deleteAll() { + db.delete(QuizContract.Questions.TABLE_NAME, null, null); + db.execSQL("delete from sqlite_sequence where name='" + QuizContract.Questions.TABLE_NAME + "';"); + } + + 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; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizModel.java new file mode 100644 index 00000000..2e5c7e09 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/data/QuizModel.java @@ -0,0 +1,77 @@ +package org.buildmlearn.toolkit.quiztemplate.data; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; + +/** + * Created by Anupam (opticod) on 11/8/16. + */ + +/** + * @brief Model used to save quiz entries in database for quiz template's simulator. + */ +public class QuizModel implements Parcelable { + public final static Creator CREATOR = new Creator() { + @Override + public QuizModel createFromParcel(Parcel parcel) { + return new QuizModel(parcel); + } + + @Override + public QuizModel[] newArray(int size) { + return new QuizModel[size]; + } + }; + private String question; + private ArrayList options; + private int correctAnswer; + + private QuizModel(Parcel in) { + this.question = in.readString(); + this.options = in.createStringArrayList(); + this.correctAnswer = in.readInt(); + } + + public QuizModel() { + + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(question); + dest.writeStringList(options); + dest.writeInt(correctAnswer); + } + + 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; + } + +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/fragment/LastFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/fragment/LastFragment.java new file mode 100644 index 00000000..366ec943 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/fragment/LastFragment.java @@ -0,0 +1,108 @@ +package org.buildmlearn.toolkit.quiztemplate.fragment; + +import android.app.FragmentManager; +import android.content.Intent; +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.quiztemplate.data.QuizDb; + +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 14/8/16. + */ + +/** + * @brief Fragment for displaying score to user in quiz template's simulator. + */ +public class LastFragment extends Fragment { + + private QuizDb db; + + 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); + + db = new QuizDb(getActivity()); + db.open(); + + int stat[] = db.getStatistics(); + + Toolbar maintoolbar = (Toolbar) rootView.findViewById(R.id.toolbar_main); + maintoolbar.setTitle(getResources().getString(R.string.app_name_quiz)); + 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; + 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; + } + }); + + ((TextView) rootView.findViewById(R.id.text)).setText(getResources().getString(R.string.completed_message_quiz)); + ((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) { + db.resetCount(); + 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(); + } + }); + + rootView.findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().finish(); + } + }); + + return rootView; + } + + @Override + public void onDestroy() { + super.onDestroy(); + db.close(); + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/fragment/QuestionFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/fragment/QuestionFragment.java new file mode 100644 index 00000000..8e49afdb --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/fragment/QuestionFragment.java @@ -0,0 +1,261 @@ +package org.buildmlearn.toolkit.quiztemplate.fragment; + +import android.app.FragmentManager; +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.quiztemplate.Constants; +import org.buildmlearn.toolkit.quiztemplate.data.QuizDb; + +import java.util.Locale; + +/** + * Created by Anupam (opticod) on 14/8/16. + */ + +/** + * @brief Question Fragment for quiz template's simulator. + */ +public class QuestionFragment extends Fragment + implements NavigationView.OnNavigationItemSelectedListener { + + private View rootView; + private QuizDb 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; + 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; + } + }); + + + 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 QuizDb(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; + + toolbar.setTitle(getResources().getString(R.string.app_name_quiz)); + + 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().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + 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/quiztemplate/fragment/SplashFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/fragment/SplashFragment.java new file mode 100644 index 00000000..3daf2a2f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/quiztemplate/fragment/SplashFragment.java @@ -0,0 +1,76 @@ +package org.buildmlearn.toolkit.quiztemplate.fragment; + +import android.app.Activity; +import android.app.FragmentManager; +import android.content.Intent; +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.quiztemplate.Constants; +import org.buildmlearn.toolkit.quiztemplate.data.DataUtils; +import org.buildmlearn.toolkit.quiztemplate.data.FetchXMLTask; +import org.buildmlearn.toolkit.quiztemplate.data.QuizDb; +import org.buildmlearn.toolkit.views.TextViewPlus; + +/** + * Created by Anupam (opticod) on 14/8/16. + */ + +/** + * @brief Splash intro Fragment for quiz template's simulator. + */ +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.app_name_quiz)); + + + rootView.findViewById(R.id.enter).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + 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(); + + } + }); + + QuizDb db = new QuizDb(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/simulator/Simulator.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/simulator/Simulator.java index 7316105e..b881dbc0 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 @@ -86,9 +86,7 @@ private void setUpTemplateEditor() { Object templateObject = templateClass.newInstance(); selectedTemplate = (TemplateInterface) templateObject; - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } 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 index 75612e9f..3b287ed3 100644 --- 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 @@ -25,6 +25,11 @@ /** * Created by Anupam (opticod) on 26/5/16. */ + +/** + * @brief Adapter for displaying Comprehension Template Editor data. + *

+ */ class ComprehensionAdapter extends BaseAdapter { @@ -89,7 +94,7 @@ public View getView(final int position, View convertView, ViewGroup parent) { 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).setText(String.format("%s) %s", 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 { @@ -159,7 +164,7 @@ private void editItem(final int position, final Context context) { boolean wrapInScrollView = true; final MaterialDialog dialog = new MaterialDialog.Builder(context) .title(R.string.quiz_edit) - .customView(R.layout.quiz_dialog_add_question, wrapInScrollView) + .customView(R.layout.quiz_dialog_add_question, true) .positiveText(R.string.quiz_add) .negativeText(R.string.quiz_cancel) .build(); 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 index c87cc6f6..f6626641 100644 --- 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 @@ -10,6 +10,7 @@ import org.buildmlearn.toolkit.views.TextViewPlus; import java.util.ArrayList; +import java.util.Locale; /** * @brief Adapter for displaying Meta Details of Comprehension Template Editor data. @@ -62,7 +63,7 @@ public View getView(final int position, View convertView, ViewGroup parent) { holder.title.setText(meta.getTitle()); holder.passage.setText(meta.getPassage()); - holder.timer.setText(meta.getTime() + " sec"); + holder.timer.setText(String.format(Locale.ENGLISH, "%d sec", meta.getTime())); convertView.setTag(holder); return convertView; 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 index 38af93cf..e9880981 100644 --- 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 @@ -32,16 +32,16 @@ import java.util.ArrayList; /** + * @brief Comprehension template code implementing methods of TemplateInterface + * * 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; private int templateId; public ComprehensionTemplate() { @@ -77,13 +77,11 @@ private static boolean validated(Context context, EditText title, EditText passa @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; @@ -129,13 +127,9 @@ public BaseAdapter loadProjectMetaEditor(Context context, Document doc) { } - @Override - public String onAttach() { - return TEMPLATE_NAME; - } - @Override public String getTitle() { + String TEMPLATE_NAME = "Comprehension Template"; return TEMPLATE_NAME; } @@ -263,7 +257,7 @@ public void addMetaData(final Activity activity) { @Override public void onClick(View v) { FileDialog fileDialog = new FileDialog(activity); - fileDialog.setFileEndsWith(".txt"); + fileDialog.setFileEndsWith(); fileDialog.addFileListener(new FileDialog.FileSelectListener() { public void fileSelected(File file) { ((TextView) dialog.findViewById(R.id.file_name)).setText(file.toString()); @@ -318,7 +312,7 @@ public void editItem(final Activity activity, final int position) { @Override public void onClick(View v) { FileDialog fileDialog = new FileDialog(activity); - fileDialog.setFileEndsWith(".txt"); + fileDialog.setFileEndsWith(); fileDialog.addFileListener(new FileDialog.FileSelectListener() { public void fileSelected(File file) { ((TextView) dialog.findViewById(R.id.file_name)).setText(file.toString()); @@ -502,8 +496,7 @@ 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) { + private 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); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationAdapter.java new file mode 100644 index 00000000..2637323f --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationAdapter.java @@ -0,0 +1,118 @@ +package org.buildmlearn.toolkit.templates; + +import android.animation.ObjectAnimator; +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.ImageButton; +import android.widget.TextView; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.views.TextViewPlus; + +import java.util.ArrayList; + +/** + * @brief Adapter for displaying Dictation Template Editor data. + *

+ * Created by Anupam (opticod) on 4/7/16. + */ +class DictationAdapter extends BaseAdapter { + + private final Context mContext; + private final ArrayList data; + + public DictationAdapter(Context mContext, ArrayList data) { + this.mContext = mContext; + this.data = data; + } + + @Override + public int getCount() { + return data.size(); + } + + @Override + public DictationModel 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) { + + final DictationHolder holder; + + if (convertView == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + convertView = inflater.inflate(R.layout.dictation_template_item, parent, false); + holder = new DictationHolder(); + convertView.setTag(holder); + + } else { + holder = (DictationHolder) convertView.getTag(); + } + + holder.title = (TextViewPlus) convertView.findViewById(R.id.dict_title); + holder.passage = (TextViewPlus) convertView.findViewById(R.id.dict_passage); + holder.expandButton = (ImageButton) convertView.findViewById(R.id.toogle_expand); + holder.collapseButton = (ImageButton) convertView.findViewById(R.id.toogle_collapse); + + final DictationModel dictation = getItem(position); + holder.passage.setText(Html.fromHtml("" + "Passage : " + " " + dictation.getPassage())); + holder.title.setText(Html.fromHtml("" + "Title : " + " " + dictation.getTitle())); + + if (dictation.isExpanded()) { + holder.expandButton.setVisibility(View.INVISIBLE); + holder.collapseButton.setVisibility(View.VISIBLE); + + } else { + holder.expandButton.setVisibility(View.VISIBLE); + holder.collapseButton.setVisibility(View.INVISIBLE); + } + holder.collapseButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + collapseTextView(holder.passage); + dictation.setExpanded(false); + holder.expandButton.setVisibility(View.VISIBLE); + holder.collapseButton.setVisibility(View.INVISIBLE); + } + }); + holder.expandButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + expandTextView(holder.passage); + dictation.setExpanded(true); + holder.expandButton.setVisibility(View.INVISIBLE); + holder.collapseButton.setVisibility(View.VISIBLE); + } + }); + + return convertView; + } + + private void expandTextView(TextView tv) { + ObjectAnimator animation = ObjectAnimator.ofInt(tv, "maxLines", tv.getLineCount()); + animation.setDuration(tv.getLineCount() * 10).start(); + } + + private void collapseTextView(TextView tv) { + ObjectAnimator animation = ObjectAnimator.ofInt(tv, "maxLines", 5); + animation.setDuration(tv.getLineCount() * 10).start(); + } + + public class DictationHolder { + public TextViewPlus title; + public TextViewPlus passage; + public ImageButton expandButton; + public ImageButton collapseButton; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationModel.java new file mode 100644 index 00000000..7adeba26 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationModel.java @@ -0,0 +1,63 @@ +package org.buildmlearn.toolkit.templates; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.Serializable; + +/** + * @brief Model class for Dictation Template Editor data + *

+ * Created by Anupam (opticod) on 4/7/16. + */ +public class DictationModel implements Serializable { + + public static final String TITLE_TAG = "dictation_title"; + public static final String PASSAGE_TAG = "dictation_passage"; + private static final String ROOT_TAG = "item"; + private String title; + private String passage; + + private boolean expanded; + + public DictationModel(String title, String passage) { + this.title = title; + this.passage = passage; + this.expanded = false; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPassage() { + return passage; + } + + public void setPassage(String passage) { + this.passage = passage; + } + + public boolean isExpanded() { + return expanded; + } + + public void setExpanded(boolean expanded) { + this.expanded = expanded; + } + + 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); + return rootElement; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationTemplate.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationTemplate.java new file mode 100644 index 00000000..cc5486b4 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/DictationTemplate.java @@ -0,0 +1,294 @@ +package org.buildmlearn.toolkit.templates; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.widget.BaseAdapter; +import android.widget.EditText; +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.dictationtemplate.fragment.SplashFragment; +import org.buildmlearn.toolkit.model.Template; +import org.buildmlearn.toolkit.model.TemplateInterface; +import org.buildmlearn.toolkit.utilities.FileDialog; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; + +/** + * @brief Dictation template code implementing methods of TemplateInterface + * + * Created by Anupam (opticod) on 4/7/16. + */ +public class DictationTemplate implements TemplateInterface { + + transient private DictationAdapter adapter; + private ArrayList dictData; + private int templateId; + + public DictationTemplate() { + dictData = new ArrayList<>(); + } + + private boolean validated(Context context, EditText title, EditText passage) { + if (title == null || passage == null) { + return false; + } + + String titleText = title.getText().toString(); + String passageText = passage.getText().toString(); + + if (titleText.equals("")) { + Toast.makeText(context, R.string.dictation_template_title_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (passageText.equals("")) { + Toast.makeText(context, R.string.dictation_template_passage_hint, Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + @Override + public BaseAdapter newTemplateEditorAdapter(Context context) { + adapter = new DictationAdapter(context, dictData); + 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) { + dictData = new ArrayList<>(); + for (Element item : data) { + String dictTitle = item.getElementsByTagName(DictationModel.TITLE_TAG).item(0).getTextContent(); + String dictPassage = item.getElementsByTagName(DictationModel.PASSAGE_TAG).item(0).getTextContent(); + dictData.add(new DictationModel(dictTitle, dictPassage)); + } + adapter = new DictationAdapter(context, dictData); + setEmptyView((Activity) context); + return adapter; + } + + @Override + public String getTitle() { + String TEMPLATE_NAME = "Dictation Template"; + return TEMPLATE_NAME; + } + + @Override + public void addItem(final Activity activity) { + + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.info_add_new_title) + .customView(R.layout.dict_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.dict_title); + final EditText passage = (EditText) dialog.findViewById(R.id.dict_passage); + + dialog.findViewById(R.id.upload).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + FileDialog fileDialog = new FileDialog(activity); + fileDialog.setFileEndsWith(); + 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.dict_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)) { + String titleText = title.getText().toString(); + String passageText = passage.getText().toString(); + + DictationModel temp = new DictationModel(titleText, passageText); + dictData.add(temp); + adapter.notifyDataSetChanged(); + setEmptyView(activity); + + 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.dict_dialog_add_edit_data, true) + .positiveText(R.string.info_template_ok) + .negativeText(R.string.info_template_cancel) + .build(); + + final DictationModel data = dictData.get(position); + + final EditText title = (EditText) dialog.findViewById(R.id.dict_title); + final EditText passage = (EditText) dialog.findViewById(R.id.dict_passage); + title.setText(data.getTitle()); + passage.setText(data.getPassage()); + + dialog.findViewById(R.id.upload).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + FileDialog fileDialog = new FileDialog(activity); + fileDialog.setFileEndsWith(); + 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.dict_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)) { + + String titleText = title.getText().toString(); + String passageText = passage.getText().toString(); + + data.setTitle(titleText); + data.setPassage(passageText); + adapter.notifyDataSetChanged(); + dialog.dismiss(); + } + } + }); + + dialog.show(); + + } + + @Override + public void deleteItem(Activity activity, int position) { + dictData.remove(position); + setEmptyView(activity); + adapter.notifyDataSetChanged(); + } + + @Override + public ArrayList getItems(Document doc) { + ArrayList itemElements = new ArrayList<>(); + + for (DictationModel data : dictData) { + + itemElements.add(data.getXml(doc)); + } + + return itemElements; + } + + @Override + public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { + return SplashFragment.newInstance(filePathWithName); + } + + @Override + public void setTemplateId(int templateId) { + this.templateId = templateId; + } + + @Override + public String getAssetsFileName(Context context) { + Template[] templates = Template.values(); + return context.getString(templates[templateId].getAssetsName()); + } + + @Override + public String getAssetsFilePath() { + return "assets/"; + } + + @Override + public String getApkFilePath() { + return "DictationApp.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 + */ + private void setEmptyView(Activity activity) { + if (dictData.size() < 1) { + 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/FlashCardModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/FlashCardModel.java index 84441282..be008f69 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 @@ -58,10 +58,6 @@ public String getHint() { return mHint; } - public String getImage() { - return mImage; - } - public Bitmap getImageBitmap() { byte[] decodedString = Base64.decode(mImage, Base64.DEFAULT); return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); 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 7925334d..4f05588e 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 @@ -22,7 +22,7 @@ import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.ToolkitApplication; -import org.buildmlearn.toolkit.flashcardtemplate.StartFragment; +import org.buildmlearn.toolkit.flashcardtemplate.fragment.SplashFragment; import org.buildmlearn.toolkit.model.Template; import org.buildmlearn.toolkit.model.TemplateInterface; import org.w3c.dom.Document; @@ -97,11 +97,6 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList return mAdapter; } - @Override - public String onAttach() { - return "Flash card template"; - } - @Override public void setTemplateId(int templateId) { this.templateId = templateId; @@ -291,7 +286,7 @@ public ArrayList getItems(Document doc) { @Override public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { - return StartFragment.newInstance(filePathWithName); + return SplashFragment.newInstance(filePathWithName); } @Override @@ -315,7 +310,7 @@ public void onActivityResult(Context context, int requestCode, int resultCode, I if (requestCode == REQUEST_TAKE_PHOTO && resultCode == Activity.RESULT_OK) { Bitmap bitmap = grabImage(context); if (bitmap != null) { - bitmap = getResizedBitmap(bitmap, 300); + bitmap = getResizedBitmap(bitmap); if (bitmap != null) { Log.d(TAG, "Bitmap not null: From Camera"); } @@ -325,7 +320,7 @@ public void onActivityResult(Context context, int requestCode, int resultCode, I stream = context.getContentResolver().openInputStream( intent.getData()); bitmap = BitmapFactory.decodeStream(stream); - bitmap = getResizedBitmap(bitmap, 300); + bitmap = getResizedBitmap(bitmap); if (bitmap != null) { Log.d(TAG, "Bitmap not null: From Gallery"); } @@ -342,16 +337,16 @@ public void onActivityResult(Context context, int requestCode, int resultCode, I } } - private Bitmap getResizedBitmap(Bitmap image, int maxSize) { + private Bitmap getResizedBitmap(Bitmap image) { int width = image.getWidth(); int height = image.getHeight(); float bitmapRatio = (float) width / (float) height; if (bitmapRatio > 0) { - width = maxSize; + width = 300; height = (int) (width / bitmapRatio); } else { - height = maxSize; + height = 300; width = (int) (height * bitmapRatio); } return Bitmap.createScaledBitmap(image, width, height, true); @@ -380,7 +375,7 @@ private Intent makePhotoIntent(String title, Context context) { mImageUri = null; try { - photo = createTemporaryFile(context, "picture", ".jpg"); + photo = createTemporaryFile(context, "picture"); mImageUri = Uri.fromFile(photo); photo.delete(); } catch (Exception e) { @@ -397,7 +392,7 @@ private Intent makePhotoIntent(String title, Context context) { return chooser; } - private File createTemporaryFile(Context context, String part, String ext) throws Exception { + private File createTemporaryFile(Context context, String part) throws Exception { ToolkitApplication toolkitApplication = (ToolkitApplication) context.getApplicationContext(); @@ -406,14 +401,13 @@ private File createTemporaryFile(Context context, String part, String ext) throw if (!tempDir.exists()) { tempDir.mkdir(); } - return File.createTempFile(part, ext, tempDir); + return File.createTempFile("picture", ".jpg", tempDir); } /** * @brief Toggles the visibility of empty text if Array has zero elements */ - @Override - public void setEmptyView(Activity activity) { + private void setEmptyView(Activity activity) { if (mData.size() < 1) { activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); } else { 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 6784810c..33ef171f 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 @@ -94,11 +94,6 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList return adapter; } - @Override - public String onAttach() { - return "Info Template"; - } - @Override public void setTemplateId(int templateId) { this.templateId = templateId; @@ -239,8 +234,7 @@ 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) { + private void setEmptyView(Activity activity) { if (infoData.size() < 1) { activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); } else { 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 d7e2533a..686e2c9c 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 @@ -12,7 +12,7 @@ import com.afollestad.materialdialogs.MaterialDialog; import org.buildmlearn.toolkit.R; -import org.buildmlearn.toolkit.learnspelling.SpellingMainFragment; +import org.buildmlearn.toolkit.learnspelling.fragment.SplashFragment; import org.buildmlearn.toolkit.model.Template; import org.buildmlearn.toolkit.model.TemplateInterface; import org.w3c.dom.Document; @@ -94,11 +94,6 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList return adapter; } - @Override - public String onAttach() { - return "Learn Spelling Template"; - } - @Override public void setTemplateId(int templateId) { this.templateId = templateId; @@ -212,7 +207,7 @@ public ArrayList getItems(Document doc) { @Override public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { - return SpellingMainFragment.newInstance(filePathWithName); + return SplashFragment.newInstance(filePathWithName); } @Override @@ -239,8 +234,7 @@ 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) { + private void setEmptyView(Activity activity) { if (mLearnSpellingData.size() < 1) { activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); } else { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchAdapter.java new file mode 100644 index 00000000..481bd021 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchAdapter.java @@ -0,0 +1,72 @@ +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 Match Template Editor data. + *

+ * Created by Anupam (opticod) on 16/7/16. + */ +class MatchAdapter extends BaseAdapter { + + private final Context context; + private final ArrayList matchData; + + public MatchAdapter(Context context, ArrayList matchData) { + this.context = context; + this.matchData = matchData; + } + + @Override + public int getCount() { + return matchData.size(); + } + + @Override + public MatchModel getItem(int position) { + return matchData.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.match_item, parent, false); + holder = new Holder(); + + holder.matchA = (TextViewPlus) convertView.findViewById(R.id.matchA); + holder.matchB = (TextViewPlus) convertView.findViewById(R.id.matchB); + + } else { + holder = (Holder) convertView.getTag(); + } + + MatchModel data = getItem(position); + holder.matchA.setText(data.getMatchA()); + holder.matchB.setText(data.getMatchB()); + + convertView.setTag(holder); + return convertView; + } + + public class Holder { + TextViewPlus matchA; + TextViewPlus matchB; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchMetaAdapter.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchMetaAdapter.java new file mode 100644 index 00000000..80c26740 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchMetaAdapter.java @@ -0,0 +1,77 @@ +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 org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.views.TextViewPlus; + +import java.util.ArrayList; + +/** + * @brief Adapter for displaying Meta Details of Match The Following Template Editor data. + *

+ * Created by Anupam (opticod) on 16/7/16. + */ +class MatchMetaAdapter extends BaseAdapter { + + private final Context mContext; + private final ArrayList data; + + public MatchMetaAdapter(Context mContext, ArrayList data) { + this.mContext = mContext; + this.data = data; + } + + @Override + public int getCount() { + return data.size(); + } + + @Override + public MatchMetaModel 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) { + + MatchMetaHolder holder; + + if (convertView == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + convertView = inflater.inflate(R.layout.match_meta_item, parent, false); + holder = new MatchMetaHolder(); + convertView.setTag(holder); + } else { + holder = (MatchMetaHolder) convertView.getTag(); + } + + holder.title = (TextViewPlus) convertView.findViewById(R.id.meta_title); + holder.first_list_title = (TextViewPlus) convertView.findViewById(R.id.first_list_title); + holder.second_list_title = (TextViewPlus) convertView.findViewById(R.id.second_list_title); + + MatchMetaModel meta = getItem(position); + + holder.title.setText(Html.fromHtml("" + "Title : " + " " + meta.getTitle())); + holder.first_list_title.setText(Html.fromHtml("" + "First List Title : " + " " + meta.getFirst_list_title())); + holder.second_list_title.setText(Html.fromHtml("" + "Second List Title : " + " " + meta.getSecond_list_title())); + + return convertView; + } + + public class MatchMetaHolder { + public TextViewPlus title; + public TextViewPlus first_list_title; + public TextViewPlus second_list_title; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchMetaModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchMetaModel.java new file mode 100644 index 00000000..8a9e86c0 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchMetaModel.java @@ -0,0 +1,66 @@ +package org.buildmlearn.toolkit.templates; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.Serializable; + +/** + * @brief Model class for Match The Following Meta Template Editor data + * Created by Anupam (opticod) on 16/7/16. + */ +public class MatchMetaModel implements Serializable { + + public static final String TITLE_TAG = "meta_title"; + public static final String FIRST_TITLE_TAG = "meta_first_list_title"; + public static final String SECOND_TITLE_TAG = "meta_second_list_title"; + private static final String ROOT_TAG = "meta_details"; + + private String title; + private String first_list_title; + private String second_list_title; + + public MatchMetaModel(String t, String A, String B) { + this.title = t; + this.first_list_title = A; + this.second_list_title = B; + } + + public String getFirst_list_title() { + return first_list_title; + } + + public void setFirst_list_title(String first_list_title) { + this.first_list_title = first_list_title; + } + + public String getSecond_list_title() { + return second_list_title; + } + + public void setSecond_list_title(String second_list_title) { + this.second_list_title = second_list_title; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Element getXml(Document doc) { + Element rootElement = doc.createElement(ROOT_TAG); + Element title_elem = doc.createElement(TITLE_TAG); + title_elem.appendChild(doc.createTextNode(title)); + rootElement.appendChild(title_elem); + Element first_list_elem = doc.createElement(FIRST_TITLE_TAG); + first_list_elem.appendChild(doc.createTextNode(first_list_title)); + rootElement.appendChild(first_list_elem); + Element second_list_elem = doc.createElement(SECOND_TITLE_TAG); + second_list_elem.appendChild(doc.createTextNode(second_list_title)); + rootElement.appendChild(second_list_elem); + return rootElement; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchModel.java new file mode 100644 index 00000000..15465805 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchModel.java @@ -0,0 +1,50 @@ +package org.buildmlearn.toolkit.templates; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.Serializable; + +/** + * @brief Model class for Match The Following Template Editor data + *

+ * Created by Anupam (opticod) on 16/7/16. + */ + +public class MatchModel implements Serializable { + + private String matchA; + private String matchB; + + public MatchModel(String A, String B) { + this.matchA = A; + this.matchB = B; + } + + public String getMatchA() { + return matchA; + } + + public void setMatchA(String matchA) { + this.matchA = matchA; + } + + public String getMatchB() { + return matchB; + } + + public void setMatchB(String matchB) { + this.matchB = matchB; + } + + public Element getXml(Document doc) { + Element rootElement = doc.createElement("item"); + Element first_list_item = doc.createElement("first_list_item"); + first_list_item.appendChild(doc.createTextNode(matchA)); + rootElement.appendChild(first_list_item); + Element second_list_item = doc.createElement("second_list_item"); + second_list_item.appendChild(doc.createTextNode(matchB)); + rootElement.appendChild(second_list_item); + return rootElement; + } +} diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchTemplate.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchTemplate.java new file mode 100644 index 00000000..072847ee --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/MatchTemplate.java @@ -0,0 +1,370 @@ +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.Toast; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; + +import org.buildmlearn.toolkit.R; +import org.buildmlearn.toolkit.matchtemplate.fragment.SplashFragment; +import org.buildmlearn.toolkit.model.Template; +import org.buildmlearn.toolkit.model.TemplateInterface; +import org.buildmlearn.toolkit.views.TextViewPlus; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.ArrayList; + +/** + * @brief Match template code implementing methods of TemplateInterface + * + * Created by Anupam (opticod) on 16/7/16. + */ +public class MatchTemplate implements TemplateInterface { + + private final ArrayList metaData; + transient private MatchAdapter adapter; + transient private MatchMetaAdapter metaAdapter; + private ArrayList MatchData; + private int templateId; + + public MatchTemplate() { + MatchData = new ArrayList<>(); + metaData = new ArrayList<>(); + } + + private static boolean validated(Context context, EditText title, EditText first_list_title, EditText second_list_title) { + if (title == null || first_list_title == null || second_list_title == null) { + return false; + } + + String titleText = title.getText().toString(); + String first_list_titleText = first_list_title.getText().toString(); + String second_list_titleText = second_list_title.getText().toString(); + + if (titleText.equals("")) { + Toast.makeText(context, R.string.comprehension_template_title_hint, Toast.LENGTH_SHORT).show(); + return false; + } else if (first_list_titleText.equals("")) { + Toast.makeText(context, R.string.match_first_list_title, Toast.LENGTH_SHORT).show(); + return false; + } else if (second_list_titleText.equals("")) { + Toast.makeText(context, R.string.match_second_list_title, Toast.LENGTH_SHORT).show(); + return false; + } + + return true; + } + + private static boolean validated(Context context, EditText first_list_title, EditText second_list_title) { + if (first_list_title == null || second_list_title == null) { + return false; + } + + String first_list_titleText = first_list_title.getText().toString(); + String second_list_titleText = second_list_title.getText().toString(); + + if (first_list_titleText.equals("")) { + Toast.makeText(context, R.string.match_first_list_title, Toast.LENGTH_SHORT).show(); + return false; + } else if (second_list_titleText.equals("")) { + Toast.makeText(context, R.string.match_second_list_title, Toast.LENGTH_SHORT).show(); + return false; + } + + return true; + } + + @Override + public BaseAdapter newTemplateEditorAdapter(Context context) { + adapter = new MatchAdapter(context, MatchData); + return adapter; + } + + public BaseAdapter newMetaEditorAdapter(Context context) { + metaAdapter = new MatchMetaAdapter(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) { + MatchData = new ArrayList<>(); + for (Element item : data) { + String first_list_item = item.getElementsByTagName("first_list_item").item(0).getTextContent(); + String second_list_item = item.getElementsByTagName("second_list_item").item(0).getTextContent(); + + MatchData.add(new MatchModel(first_list_item, second_list_item)); + + } + adapter = new MatchAdapter(context, MatchData); + return adapter; + } + + public BaseAdapter loadProjectMetaEditor(Context context, Document doc) { + + String title = doc.getElementsByTagName(MatchMetaModel.TITLE_TAG).item(0).getTextContent(); + String first_list_title = doc.getElementsByTagName(MatchMetaModel.FIRST_TITLE_TAG).item(0).getTextContent(); + String second_list_title = doc.getElementsByTagName(MatchMetaModel.SECOND_TITLE_TAG).item(0).getTextContent(); + metaData.add(new MatchMetaModel(title, first_list_title, second_list_title)); + metaAdapter = new MatchMetaAdapter(context, metaData); + setEmptyView((Activity) context); + + return metaAdapter; + + } + + @Override + public String getTitle() { + String TEMPLATE_NAME = "Match Template"; + return TEMPLATE_NAME; + } + + @Override + public void addItem(final Activity activity) { + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.match_dialog_add_title) + .customView(R.layout.match_dialog_add_edit, true) + .positiveText(R.string.quiz_add) + .negativeText(R.string.quiz_cancel) + .build(); + + final EditText first_list_item = (EditText) dialog.findViewById(R.id.first_list_item); + final EditText second_list_item = (EditText) dialog.findViewById(R.id.second_list_item); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (validated(activity, first_list_item, second_list_item)) { + String first_list_itemText = first_list_item.getText().toString(); + String second_list_itemText = second_list_item.getText().toString(); + + MatchModel temp = new MatchModel(first_list_itemText, second_list_itemText); + MatchData.add(temp); + adapter.notifyDataSetChanged(); + setEmptyView(activity); + dialog.dismiss(); + } + + } + }); + + 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.match_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 first_list_title = (EditText) dialog.findViewById(R.id.meta_first_list_title); + final EditText second_list_title = (EditText) dialog.findViewById(R.id.meta_second_list_title); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (validated(activity, title, first_list_title, second_list_title)) { + + String titleText = title.getText().toString(); + String first_list_titleText = first_list_title.getText().toString(); + String second_list_titleText = second_list_title.getText().toString(); + MatchMetaModel temp = new MatchMetaModel(titleText, first_list_titleText, second_list_titleText); + 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.match_meta_dialog_add_edit_data, true) + .positiveText(R.string.info_template_ok) + .negativeText(R.string.info_template_cancel) + .build(); + + final MatchMetaModel data = metaData.get(0); + + final EditText title = (EditText) dialog.findViewById(R.id.meta_title); + final EditText first_list_title = (EditText) dialog.findViewById(R.id.meta_first_list_title); + final EditText second_list_title = (EditText) dialog.findViewById(R.id.meta_second_list_title); + + title.setText(data.getTitle()); + first_list_title.setText(data.getFirst_list_title()); + second_list_title.setText(data.getSecond_list_title()); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (validated(activity, title, first_list_title, second_list_title)) { + + String titleText = title.getText().toString(); + String first_list_titleText = first_list_title.getText().toString(); + String second_list_titleText = second_list_title.getText().toString(); + + data.setTitle(titleText); + data.setFirst_list_title(first_list_titleText); + data.setSecond_list_title(second_list_titleText); + metaAdapter.notifyDataSetChanged(); + dialog.dismiss(); + } + } + }); + + dialog.show(); + + } else { + + final MatchModel data = MatchData.get(position); + + final MaterialDialog dialog = new MaterialDialog.Builder(activity) + .title(R.string.match_dialog_edit_title) + .customView(R.layout.match_dialog_add_edit, true) + .positiveText(R.string.info_template_ok) + .negativeText(R.string.info_template_cancel) + .build(); + + + final EditText first_list_item = (EditText) dialog.findViewById(R.id.first_list_item); + final EditText second_list_item = (EditText) dialog.findViewById(R.id.second_list_item); + + first_list_item.setText(data.getMatchA()); + second_list_item.setText(data.getMatchB()); + + dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (validated(activity, first_list_item, second_list_item)) { + + String first_list_itemText = first_list_item.getText().toString(); + String second_list_itemText = second_list_item.getText().toString(); + + data.setMatchA(first_list_itemText); + data.setMatchB(second_list_itemText); + + adapter.notifyDataSetChanged(); + dialog.dismiss(); + } + } + }); + + dialog.show(); + } + } + + @Override + public void deleteItem(Activity activity, int position) { + if (position == -2) { + metaData.remove(0); + setEmptyView(activity); + metaAdapter.notifyDataSetChanged(); + } else { + MatchData.remove(position); + setEmptyView(activity); + adapter.notifyDataSetChanged(); + } + } + + @Override + public ArrayList getItems(Document doc) { + ArrayList itemElements = new ArrayList<>(); + + for (MatchMetaModel data : metaData) { + itemElements.add(data.getXml(doc)); + } + + for (MatchModel data : MatchData) { + + itemElements.add(data.getXml(doc)); + } + + return itemElements; + } + + @Override + public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { + return SplashFragment.newInstance(filePathWithName); + } + + @Override + public void setTemplateId(int templateId) { + this.templateId = templateId; + } + + @Override + public String getAssetsFileName(Context context) { + Template[] templates = Template.values(); + return context.getString(templates[templateId].getAssetsName()); + } + + @Override + public String getAssetsFilePath() { + return "assets/"; + } + + @Override + public String getApkFilePath() { + return "MatchApp.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 + */ + private 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 (MatchData.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 (MatchData.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); + } + } +} 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 94fe4d2a..6da8d24d 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 @@ -91,7 +91,7 @@ public View getView(final int position, View convertView, ViewGroup parent) { 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).setText(String.format("%s) %s", 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 { @@ -161,7 +161,7 @@ private void editItem(final int position, final Context context) { boolean wrapInScrollView = true; final MaterialDialog dialog = new MaterialDialog.Builder(context) .title(R.string.quiz_edit) - .customView(R.layout.quiz_dialog_add_question, wrapInScrollView) + .customView(R.layout.quiz_dialog_add_question, true) .positiveText(R.string.quiz_add) .negativeText(R.string.quiz_cancel) .build(); diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizModel.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizModel.java index 6a52da34..cd8e8669 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizModel.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/templates/QuizModel.java @@ -14,9 +14,9 @@ public class QuizModel implements Serializable { - private String question; - private ArrayList options; - private int correctAnswer; + private final String question; + private final ArrayList options; + private final int correctAnswer; private boolean isSelected; public QuizModel(String question, ArrayList options, int correctAnswer) { @@ -30,26 +30,14 @@ 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"); 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 ab77a70e..78e45fed 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 @@ -15,7 +15,7 @@ import org.buildmlearn.toolkit.R; import org.buildmlearn.toolkit.model.Template; import org.buildmlearn.toolkit.model.TemplateInterface; -import org.buildmlearn.toolkit.quiztemplate.TFTQuizFragment; +import org.buildmlearn.toolkit.quiztemplate.fragment.SplashFragment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -84,11 +84,6 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList return mAdapter; } - @Override - public String onAttach() { - return "Quiz Template"; - } - @Override public void setTemplateId(int templateId) { this.templateId = templateId; @@ -297,7 +292,7 @@ public ArrayList getItems(Document doc) { @Override public android.support.v4.app.Fragment getSimulatorFragment(String filePathWithName) { - return TFTQuizFragment.newInstance(filePathWithName); + return SplashFragment.newInstance(filePathWithName); } @Override @@ -351,8 +346,7 @@ private int getCheckedAnswer(ArrayList buttons) { /** * @brief Toggles the visibility of empty text if Array has zero elements */ - @Override - public void setEmptyView(Activity activity) { + private void setEmptyView(Activity activity) { if (quizData.size() < 1) { activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); } else { 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 index bab0fdc8..efff4ffb 100644 --- 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 @@ -38,6 +38,8 @@ import java.util.ArrayList; /** + * @brief Video template code implementing methods of TemplateInterface + * * Created by Anupam (opticod) on 4/5/16. */ public class VideoCollectionTemplate implements TemplateInterface { @@ -46,7 +48,6 @@ public class VideoCollectionTemplate implements TemplateInterface { 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; @@ -146,20 +147,18 @@ public BaseAdapter loadProjectTemplateEditor(Context context, ArrayList return adapter; } - @Override - public String onAttach() { - return TEMPLATE_NAME; - } - @Override public String getTitle() { + String TEMPLATE_NAME = "VideoCollection Template"; return TEMPLATE_NAME; } private String convertLink(String link) { if (link.contains(YOUTUBE)) { - if (!link.contains("www.")) { + if (link.contains("https://m." + YOUTUBE)) { + link = link.replace("https://m." + YOUTUBE, "https://www." + YOUTUBE); + } else if (!link.contains("www.")) { link = "https://www." + link; } else if (!(link.contains("http:") || link.contains("https:"))) { link = "https://" + link; @@ -361,8 +360,7 @@ 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) { + private void setEmptyView(Activity activity) { if (videoData.size() < 1) { activity.findViewById(R.id.empty).setVisibility(View.VISIBLE); } else { 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 deleted file mode 100644 index 14d28d84..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Alias.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.buildmlearn.toolkit.utilities; - -/** - * @brief Model class for storing Alias data for keystore. - */ -class Alias { - - 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; - } - - public void setId(long id) { - this.id = id; - } - - public Keystore getKeystore() { - return keystore; - } - - public void setKeystore(Keystore keystore) { - this.keystore = keystore; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDisplayName() { - return displayName; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public boolean isSelected() { - return selected; - } - - public void setSelected(boolean selected) { - this.selected = selected; - } - - public boolean rememberPassword() { - return rememberPassword; - } - - public void setRememberPassword(boolean rememberPassword) { - this.rememberPassword = rememberPassword; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Alias alias = (Alias) o; - - return id == alias.id; - - } - - @Override - public int hashCode() { - return (int) (id ^ (id >>> 32)); - } -} 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 index 2e8f84bc..290ddf2a 100644 --- 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 @@ -14,6 +14,8 @@ import java.util.List; /** + * @brief Programmed dialog box to select file from storage. + * * Created by Anupam (opticod) on 30/5/16. */ public class FileDialog { @@ -79,7 +81,7 @@ 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; + boolean endsWith = fileEndsWith == null || filename.toLowerCase().endsWith(fileEndsWith); return endsWith || sel.isDirectory(); } } @@ -98,8 +100,8 @@ private File getChosenFile(String fileChosen) { else return new File(currentPath, fileChosen); } - public void setFileEndsWith(String fileEndsWith) { - this.fileEndsWith = fileEndsWith != null ? fileEndsWith.toLowerCase() : fileEndsWith; + public void setFileEndsWith() { + this.fileEndsWith = ".txt" != null ? ".txt".toLowerCase() : ".txt"; } public interface FileSelectListener { @@ -121,10 +123,6 @@ public void fireEvent(FireHandler fireHandler) { } } - 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 4f76569b..714417f2 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 @@ -55,7 +55,7 @@ public static void unZip(String zipFilePath, String destinationFolder) throws IO * @throws IOException Exception thrown in case of some error. * @brief Unzips a compressed file (.zip, .apk) */ - public static void unZip(InputStream zipInputStream, String destinationFolder) throws IOException { + public static void unZip(InputStream zipInputStream, String destinationFolder) { int size; byte[] buffer = new byte[BUFFER_SIZE]; try { @@ -67,8 +67,7 @@ public static void unZip(InputStream zipInputStream, String destinationFolder) t f.mkdirs(); } - ZipInputStream zin = new ZipInputStream(new BufferedInputStream(zipInputStream, BUFFER_SIZE)); - try { + try (ZipInputStream zin = new ZipInputStream(new BufferedInputStream(zipInputStream, BUFFER_SIZE))) { ZipEntry ze; while ((ze = zin.getNextEntry()) != null) { String path = destinationFolder + ze.getName(); @@ -82,7 +81,7 @@ public static void unZip(InputStream zipInputStream, String destinationFolder) t File parentDir = unzipFile.getParentFile(); if (null != parentDir && !parentDir.isDirectory()) { - parentDir.mkdirs(); + parentDir.mkdirs(); } FileOutputStream out = new FileOutputStream(unzipFile, false); @@ -99,8 +98,6 @@ public static void unZip(InputStream zipInputStream, String destinationFolder) t } } } - } finally { - zin.close(); } } catch (Exception e) { e.printStackTrace(); @@ -149,8 +146,8 @@ public static boolean equalContent(File file1, File file2) { //Indenitifier with 1 suffix corresponds for file1 byte[] buffer1 = new byte[BUFFER_SIZE]; byte[] buffer2 = new byte[BUFFER_SIZE]; - int read1 = -1; - int read2 = -1; + int read1; + int read2; InputStream is1 = null; InputStream is2 = null; try { @@ -182,7 +179,7 @@ public static boolean equalContent(File file1, File file2) { is1.close(); if(is2!=null) is2.close(); - } catch (IOException e) { + } catch (IOException ignored) { } 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 index 702bb772..92772e61 100644 --- 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 @@ -6,6 +6,8 @@ import android.view.inputmethod.InputMethodManager; /** + * @brief Helper functions used to hide the soft keyboard. + * * User : opticod(Anupam Das) * Date : 24/2/16. */ 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 deleted file mode 100644 index 7c00216b..00000000 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/Keystore.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.buildmlearn.toolkit.utilities; - -import java.util.ArrayList; -import java.util.List; - - -/** - * @brief Model class for storing Keystore details - */ -public class Keystore { - - private final List aliases = new ArrayList<>(); - private long id; - private String path; - private String password; - private boolean rememberPassword; - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public void addAlias(Alias alias) { - aliases.add(alias); - } - - public List getAliases() { - return aliases; - } - - public boolean rememberPassword() { - return rememberPassword; - } - - public void setRememberPassword(boolean rememberPassword) { - this.rememberPassword = rememberPassword; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Keystore keystore = (Keystore) o; - - return id == keystore.id; - - } - - @Override - public int hashCode() { - return (int) (id ^ (id >>> 32)); - } -} 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 index 887f67f2..905787df 100644 --- 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 @@ -5,6 +5,8 @@ import android.net.NetworkInfo; /** + * @brief Helper functions used to check network connection. + * * Created by Anupam(opticod) on 10/5/16. */ public class NetworkUtils { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/RestoreThread.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/RestoreThread.java index 1cd7c183..be70f0f2 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/RestoreThread.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/RestoreThread.java @@ -18,13 +18,10 @@ * @brief Class for extracting .buildmlearn file from apk. */ public class RestoreThread extends Thread { - private static final String TAG = "RestoreThread"; private static final String TEMP_FOLDER = "rtf"; - private static String assetDirectory = "assets"; - private String assetFileName; - private Context context; - private InputStream zipInputStream; - private ToolkitApplication toolkit; + private final Context context; + private final InputStream zipInputStream; + private final ToolkitApplication toolkit; private OnRestoreComplete listener; @@ -41,7 +38,8 @@ public void setRestoreListener(OnRestoreComplete listener) { @Override public void run() { try { - File assetDir = new File(toolkit.getUnZipDir() + TEMP_FOLDER + "/" + assetDirectory); + String assetDirectory = "assets"; + File assetDir = new File(ToolkitApplication.getUnZipDir() + TEMP_FOLDER + "/" + assetDirectory); assetDir.mkdirs(); //Deleting Previous Files if Exists File[] templateAssets = assetDir.listFiles(); @@ -50,7 +48,7 @@ public void run() { } //Unzipping - FileUtils.unZip(zipInputStream, toolkit.getUnZipDir() + TEMP_FOLDER); + FileUtils.unZip(zipInputStream, ToolkitApplication.getUnZipDir() + TEMP_FOLDER); String files[] = assetDir.list(); File data = null; Template[] templates = Template.values(); @@ -71,7 +69,7 @@ public void run() { if (data == null) { if (listener != null) - listener.onFail(new Exception("Assets Data not Found!")); + listener.onFail(); return; } @@ -79,11 +77,6 @@ public void run() { listener.onSuccess(data); - } catch (IOException e) { - if (listener != null) { - listener.onFail(e); - } - e.printStackTrace(); } finally { try { @@ -98,6 +91,8 @@ public void run() { public interface OnRestoreComplete { void onSuccess(File assetFile); + void onFail(); + void onFail(Exception e); } } 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 768e42fa..01d6e995 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 @@ -53,6 +53,7 @@ import java.io.InputStream; import java.security.UnrecoverableKeyException; import java.util.Calendar; +import java.util.Objects; import kellinwood.security.zipsigner.AutoKeyException; import kellinwood.security.zipsigner.ZipSigner; @@ -152,7 +153,7 @@ public void run() { FileUtils.copyAssets(context, keyDetails.getAssetsPath(), toolkit.getApkDir()); try { - FileUtils.unZip(toolkit.getApkDir() + assetsApk, toolkit.getUnZipDir() + TEMP_FOLDER); + FileUtils.unZip(toolkit.getApkDir() + assetsApk, ToolkitApplication.getUnZipDir() + TEMP_FOLDER); } catch (IOException e) { e.printStackTrace(); } @@ -163,7 +164,7 @@ public void run() { Calendar rightNow = Calendar.getInstance(); packageName += String.valueOf(rightNow.getTimeInMillis()); - modifyManifest(new String[]{toolkit.getUnZipDir() + TEMP_FOLDER + "/AndroidManifest.xml", packageName}); + modifyManifest(new String[]{ToolkitApplication.getUnZipDir() + TEMP_FOLDER + "/AndroidManifest.xml", packageName}); } catch (Exception e) { if (listener != null) { listener.onFail(e); @@ -172,7 +173,7 @@ public void run() { } - File folder = new File(toolkit.getUnZipDir() + TEMP_FOLDER + "/" + assetFilePath); + File folder = new File(ToolkitApplication.getUnZipDir() + TEMP_FOLDER + "/" + assetFilePath); if (!folder.exists()) { folder.mkdir(); @@ -184,7 +185,7 @@ public void run() { } File src = new File(projectFile); - File dest = new File(toolkit.getUnZipDir() + TEMP_FOLDER + "/" + assetFilePath + assetFileName); + File dest = new File(ToolkitApplication.getUnZipDir() + TEMP_FOLDER + "/" + assetFilePath + assetFileName); try { new FileWriter(dest.getAbsoluteFile(), true); @@ -203,7 +204,7 @@ public void run() { } try { - FileUtils.zipFolder(toolkit.getUnZipDir() + TEMP_FOLDER); + FileUtils.zipFolder(ToolkitApplication.getUnZipDir() + TEMP_FOLDER); } catch (IOException e) { if (listener != null) { listener.onFail(e); @@ -211,7 +212,7 @@ public void run() { e.printStackTrace(); } - String inputFile = toolkit.getUnZipDir() + TEMP_FOLDER + ".zip"; + String inputFile = ToolkitApplication.getUnZipDir() + TEMP_FOLDER + ".zip"; try { if (finalApk == null) { throw new IllegalArgumentException("Parameter outputFile is null"); @@ -344,7 +345,7 @@ public void attr(String ns, String name, int resourceId, int type, Object val) { name = null; } - if (name != oldName || val != oldVal) { + if (!Objects.equals(name, oldName) || val != oldVal) { changed = true; if (!didLogNodeName) { didLogNodeName = true; 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 1226f1a1..353602bf 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 @@ -43,7 +43,7 @@ public String getString(Item item, Object... args) { return resources.getString(R.string.GeneratingSignatureBlock); case COPYING_ZIP_ENTRY: // return String.format("Copying zip entry %d of %d", args[0], args[1]); - return resources.getString(R.string.CopyingZipEntry, (int) args[0], (int) args[1]); + return resources.getString(R.string.CopyingZipEntry, args[0], args[1]); default: throw new IllegalArgumentException("Unknown item " + item); } diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/diff_match_patch.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/diff_match_patch.java new file mode 100644 index 00000000..b693a804 --- /dev/null +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/utilities/diff_match_patch.java @@ -0,0 +1,2602 @@ +/* + * Diff Match and Patch + * + * Copyright 2006 Google Inc. + * http://code.google.com/p/google-diff-match-patch/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Original code from http://code.google.com/p/google-diff-match-patch/ + * has been modified by Anupam Das to handle the "word-mode" feature and its 'diff_prettyHtml' + * method is also changed. + */ + +package org.buildmlearn.toolkit.utilities; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/* + * Functions for diff, match and patch. + * Computes the difference between two texts to create a patch. + * Applies the patch onto another text, allowing for errors. + * + * @author fraser@google.com (Neil Fraser) + */ + +/** + * Class containing the diff, match and patch methods. + * Also contains the behaviour settings. + */ +public class diff_match_patch { + + // Defaults. + // Set these on your diff_match_patch instance to override the defaults. + + /** + * Number of seconds to map a diff before giving up (0 for infinity). + */ + public float Diff_Timeout = 1.0f; + /** + * Cost of an empty edit operation in terms of edit characters. + */ + public short Diff_EditCost = 4; + /** + * At what point is no match declared (0.0 = perfection, 1.0 = very loose). + */ + public float Match_Threshold = 0.5f; + /** + * How far to search for a match (0 = exact location, 1000+ = broad match). + * A match this many characters away from the expected location will add + * 1.0 to the score (0.0 is a perfect match). + */ + public int Match_Distance = 1000; + /** + * When deleting a large block of text (over ~64 characters), how close do + * the contents have to be to match the expected contents. (0.0 = perfection, + * 1.0 = very loose). Note that Match_Threshold controls how closely the + * end points of a delete need to match. + */ + public float Patch_DeleteThreshold = 0.5f; + /** + * Chunk size for context length. + */ + public short Patch_Margin = 4; + + /** + * The number of bits in an int. + */ + private short Match_MaxBits = 32; + // Define some regex patterns for matching boundaries. + private Pattern BLANKLINEEND + = Pattern.compile("\\n\\r?\\n\\Z", Pattern.DOTALL); + + + // DIFF FUNCTIONS + private Pattern BLANKLINESTART + = Pattern.compile("\\A\\r?\\n\\r?\\n", Pattern.DOTALL); + + /** + * Unescape selected chars for compatability with JavaScript's encodeURI. + * In speed critical applications this could be dropped since the + * receiving application will certainly decode these fine. + * Note that this function is case-sensitive. Thus "%3f" would not be + * unescaped. But this is ok because it is only called with the output of + * URLEncoder.encode which returns uppercase hex. + *

+ * Example: "%3F" -> "?", "%24" -> "$", etc. + * + * @param str The string to escape. + * @return The escaped string. + */ + private static String unescapeForEncodeUriCompatability(String str) { + return str.replace("%21", "!").replace("%7E", "~") + .replace("%27", "'").replace("%28", "(").replace("%29", ")") + .replace("%3B", ";").replace("%2F", "/").replace("%3F", "?") + .replace("%3A", ":").replace("%40", "@").replace("%26", "&") + .replace("%3D", "=").replace("%2B", "+").replace("%24", "$") + .replace("%2C", ",").replace("%23", "#"); + } + + /** + * Find the differences between two texts. + * Run a faster, slightly less optimal diff. + * This method allows the 'checklines' of diff_main() to be optional. + * Most of the time checklines is wanted, so default to true. + * + * @param text1 Old string to be diffed. + * @param text2 New string to be diffed. + * @return Linked List of Diff objects. + */ + public LinkedList diff_main(String text1, String text2) { + return diff_main(text1, text2, true); + } + + /** + * Find the differences between two texts. + * + * @param text1 Old string to be diffed. + * @param text2 New string to be diffed. + * @param checklines Speedup flag. If false, then don't run a + * line-level diff first to identify the changed areas. + * If true, then run a faster slightly less optimal diff. + * @return Linked List of Diff objects. + */ + public LinkedList diff_main(String text1, String text2, + boolean checklines) { + // Set a deadline by which time the diff must be complete. + long deadline; + if (Diff_Timeout <= 0) { + deadline = Long.MAX_VALUE; + } else { + deadline = System.currentTimeMillis() + (long) (Diff_Timeout * 1000); + } + return diff_main(text1, text2, checklines, deadline); + } + + /** + * Find the differences between two texts. Simplifies the problem by + * stripping any common prefix or suffix off the texts before diffing. + * + * @param text1 Old string to be diffed. + * @param text2 New string to be diffed. + * @param checklines Speedup flag. If false, then don't run a + * line-level diff first to identify the changed areas. + * If true, then run a faster slightly less optimal diff. + * @param deadline Time when the diff should be complete by. Used + * internally for recursive calls. Users should set DiffTimeout instead. + * @return Linked List of Diff objects. + */ + private LinkedList diff_main(String text1, String text2, + boolean checklines, long deadline) { + // Check for null inputs. + if (text1 == null || text2 == null) { + throw new IllegalArgumentException("Null inputs. (diff_main)"); + } + + // Check for equality (speedup). + LinkedList diffs; + if (text1.equals(text2)) { + diffs = new LinkedList(); + if (text1.length() != 0) { + diffs.add(new Diff(Operation.EQUAL, text1)); + } + return diffs; + } + + // Trim off common prefix (speedup). + int commonlength = diff_commonPrefix(text1, text2); + String commonprefix = text1.substring(0, commonlength); + text1 = text1.substring(commonlength); + text2 = text2.substring(commonlength); + + // Trim off common suffix (speedup). + commonlength = diff_commonSuffix(text1, text2); + String commonsuffix = text1.substring(text1.length() - commonlength); + text1 = text1.substring(0, text1.length() - commonlength); + text2 = text2.substring(0, text2.length() - commonlength); + + // Compute the diff on the middle block. + diffs = diff_compute(text1, text2, checklines, deadline); + + // Restore the prefix and suffix. + if (commonprefix.length() != 0) { + diffs.addFirst(new Diff(Operation.EQUAL, commonprefix)); + } + if (commonsuffix.length() != 0) { + diffs.addLast(new Diff(Operation.EQUAL, commonsuffix)); + } + + diff_cleanupMerge(diffs); + return diffs; + } + + public LinkedList diff_WordMode(String text1, String text2) { + LinesToCharsResult linesResult = diff_wordsToChars(text1, text2); + String lineText1 = linesResult.chars1; + String lineText2 = linesResult.chars2; + LinkedList diffs = diff_main(lineText1, lineText2, false); + diff_charsToLines(diffs, linesResult.lineArray); + return diffs; + } + + /** + * Find the differences between two texts. Assumes that the texts do not + * have any common prefix or suffix. + * + * @param text1 Old string to be diffed. + * @param text2 New string to be diffed. + * @param checklines Speedup flag. If false, then don't run a + * line-level diff first to identify the changed areas. + * If true, then run a faster slightly less optimal diff. + * @param deadline Time when the diff should be complete by. + * @return Linked List of Diff objects. + */ + private LinkedList diff_compute(String text1, String text2, + boolean checklines, long deadline) { + LinkedList diffs = new LinkedList(); + + if (text1.length() == 0) { + // Just add some text (speedup). + diffs.add(new Diff(Operation.INSERT, text2)); + return diffs; + } + + if (text2.length() == 0) { + // Just delete some text (speedup). + diffs.add(new Diff(Operation.DELETE, text1)); + return diffs; + } + + String longtext = text1.length() > text2.length() ? text1 : text2; + String shorttext = text1.length() > text2.length() ? text2 : text1; + int i = longtext.indexOf(shorttext); + if (i != -1) { + // Shorter text is inside the longer text (speedup). + Operation op = (text1.length() > text2.length()) ? + Operation.DELETE : Operation.INSERT; + diffs.add(new Diff(op, longtext.substring(0, i))); + diffs.add(new Diff(Operation.EQUAL, shorttext)); + diffs.add(new Diff(op, longtext.substring(i + shorttext.length()))); + return diffs; + } + + if (shorttext.length() == 1) { + // Single character string. + // After the previous speedup, the character can't be an equality. + diffs.add(new Diff(Operation.DELETE, text1)); + diffs.add(new Diff(Operation.INSERT, text2)); + return diffs; + } + + // Check to see if the problem can be split in two. + String[] hm = diff_halfMatch(text1, text2); + if (hm != null) { + // A half-match was found, sort out the return data. + String text1_a = hm[0]; + String text1_b = hm[1]; + String text2_a = hm[2]; + String text2_b = hm[3]; + String mid_common = hm[4]; + // Send both pairs off for separate processing. + LinkedList diffs_a = diff_main(text1_a, text2_a, + checklines, deadline); + LinkedList diffs_b = diff_main(text1_b, text2_b, + checklines, deadline); + // Merge the results. + diffs = diffs_a; + diffs.add(new Diff(Operation.EQUAL, mid_common)); + diffs.addAll(diffs_b); + return diffs; + } + + if (checklines && text1.length() > 100 && text2.length() > 100) { + return diff_lineMode(text1, text2, deadline); + } + + return diff_bisect(text1, text2, deadline); + } + + /** + * Do a quick line-level diff on both strings, then rediff the parts for + * greater accuracy. + * This speedup can produce non-minimal diffs. + * + * @param text1 Old string to be diffed. + * @param text2 New string to be diffed. + * @param deadline Time when the diff should be complete by. + * @return Linked List of Diff objects. + */ + private LinkedList diff_lineMode(String text1, String text2, + long deadline) { + // Scan the text on a line-by-line basis first. + LinesToCharsResult b = diff_linesToChars(text1, text2); + text1 = b.chars1; + text2 = b.chars2; + List linearray = b.lineArray; + + LinkedList diffs = diff_main(text1, text2, false, deadline); + + // Convert the diff back to original text. + diff_charsToLines(diffs, linearray); + // Eliminate freak matches (e.g. blank lines) + diff_cleanupSemantic(diffs); + + // Rediff any replacement blocks, this time character-by-character. + // Add a dummy entry at the end. + diffs.add(new Diff(Operation.EQUAL, "")); + int count_delete = 0; + int count_insert = 0; + String text_delete = ""; + String text_insert = ""; + ListIterator pointer = diffs.listIterator(); + Diff thisDiff = pointer.next(); + while (thisDiff != null) { + switch (thisDiff.operation) { + case INSERT: + count_insert++; + text_insert += thisDiff.text; + break; + case DELETE: + count_delete++; + text_delete += thisDiff.text; + break; + case EQUAL: + // Upon reaching an equality, check for prior redundancies. + if (count_delete >= 1 && count_insert >= 1) { + // Delete the offending records and add the merged ones. + pointer.previous(); + for (int j = 0; j < count_delete + count_insert; j++) { + pointer.previous(); + pointer.remove(); + } + for (Diff newDiff : diff_main(text_delete, text_insert, false, + deadline)) { + pointer.add(newDiff); + } + } + count_insert = 0; + count_delete = 0; + text_delete = ""; + text_insert = ""; + break; + } + thisDiff = pointer.hasNext() ? pointer.next() : null; + } + diffs.removeLast(); // Remove the dummy entry at the end. + + return diffs; + } + + /** + * Find the 'middle snake' of a diff, split the problem in two + * and return the recursively constructed diff. + * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations. + * + * @param text1 Old string to be diffed. + * @param text2 New string to be diffed. + * @param deadline Time at which to bail if not yet complete. + * @return LinkedList of Diff objects. + */ + protected LinkedList diff_bisect(String text1, String text2, + long deadline) { + // Cache the text lengths to prevent multiple calls. + int text1_length = text1.length(); + int text2_length = text2.length(); + int max_d = (text1_length + text2_length + 1) / 2; + int v_offset = max_d; + int v_length = 2 * max_d; + int[] v1 = new int[v_length]; + int[] v2 = new int[v_length]; + for (int x = 0; x < v_length; x++) { + v1[x] = -1; + v2[x] = -1; + } + v1[v_offset + 1] = 0; + v2[v_offset + 1] = 0; + int delta = text1_length - text2_length; + // If the total number of characters is odd, then the front path will + // collide with the reverse path. + boolean front = (delta % 2 != 0); + // Offsets for start and end of k loop. + // Prevents mapping of space beyond the grid. + int k1start = 0; + int k1end = 0; + int k2start = 0; + int k2end = 0; + for (int d = 0; d < max_d; d++) { + // Bail out if deadline is reached. + if (System.currentTimeMillis() > deadline) { + break; + } + + // Walk the front path one step. + for (int k1 = -d + k1start; k1 <= d - k1end; k1 += 2) { + int k1_offset = v_offset + k1; + int x1; + if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) { + x1 = v1[k1_offset + 1]; + } else { + x1 = v1[k1_offset - 1] + 1; + } + int y1 = x1 - k1; + while (x1 < text1_length && y1 < text2_length + && text1.charAt(x1) == text2.charAt(y1)) { + x1++; + y1++; + } + v1[k1_offset] = x1; + if (x1 > text1_length) { + // Ran off the right of the graph. + k1end += 2; + } else if (y1 > text2_length) { + // Ran off the bottom of the graph. + k1start += 2; + } else if (front) { + int k2_offset = v_offset + delta - k1; + if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) { + // Mirror x2 onto top-left coordinate system. + int x2 = text1_length - v2[k2_offset]; + if (x1 >= x2) { + // Overlap detected. + return diff_bisectSplit(text1, text2, x1, y1, deadline); + } + } + } + } + + // Walk the reverse path one step. + for (int k2 = -d + k2start; k2 <= d - k2end; k2 += 2) { + int k2_offset = v_offset + k2; + int x2; + if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) { + x2 = v2[k2_offset + 1]; + } else { + x2 = v2[k2_offset - 1] + 1; + } + int y2 = x2 - k2; + while (x2 < text1_length && y2 < text2_length + && text1.charAt(text1_length - x2 - 1) + == text2.charAt(text2_length - y2 - 1)) { + x2++; + y2++; + } + v2[k2_offset] = x2; + if (x2 > text1_length) { + // Ran off the left of the graph. + k2end += 2; + } else if (y2 > text2_length) { + // Ran off the top of the graph. + k2start += 2; + } else if (!front) { + int k1_offset = v_offset + delta - k2; + if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) { + int x1 = v1[k1_offset]; + int y1 = v_offset + x1 - k1_offset; + // Mirror x2 onto top-left coordinate system. + x2 = text1_length - x2; + if (x1 >= x2) { + // Overlap detected. + return diff_bisectSplit(text1, text2, x1, y1, deadline); + } + } + } + } + } + // Diff took too long and hit the deadline or + // number of diffs equals number of characters, no commonality at all. + LinkedList diffs = new LinkedList(); + diffs.add(new Diff(Operation.DELETE, text1)); + diffs.add(new Diff(Operation.INSERT, text2)); + return diffs; + } + + /** + * Given the location of the 'middle snake', split the diff in two parts + * and recurse. + * + * @param text1 Old string to be diffed. + * @param text2 New string to be diffed. + * @param x Index of split point in text1. + * @param y Index of split point in text2. + * @param deadline Time at which to bail if not yet complete. + * @return LinkedList of Diff objects. + */ + private LinkedList diff_bisectSplit(String text1, String text2, + int x, int y, long deadline) { + String text1a = text1.substring(0, x); + String text2a = text2.substring(0, y); + String text1b = text1.substring(x); + String text2b = text2.substring(y); + + // Compute both diffs serially. + LinkedList diffs = diff_main(text1a, text2a, false, deadline); + LinkedList diffsb = diff_main(text1b, text2b, false, deadline); + + diffs.addAll(diffsb); + return diffs; + } + + /** + * Split two texts into a list of strings. Reduce the texts to a string of + * hashes where each Unicode character represents one line. + * + * @param text1 First string. + * @param text2 Second string. + * @return An object containing the encoded text1, the encoded text2 and + * the List of unique strings. The zeroth element of the List of + * unique strings is intentionally blank. + */ + protected LinesToCharsResult diff_linesToChars(String text1, String text2) { + List lineArray = new ArrayList(); + Map lineHash = new HashMap(); + // e.g. linearray[4] == "Hello\n" + // e.g. linehash.get("Hello\n") == 4 + + // "\x00" is a valid character, but various debuggers don't like it. + // So we'll insert a junk entry to avoid generating a null character. + lineArray.add(""); + + String chars1 = diff_linesToCharsMunge(text1, lineArray, lineHash); + String chars2 = diff_linesToCharsMunge(text2, lineArray, lineHash); + return new LinesToCharsResult(chars1, chars2, lineArray); + } + + /** + * Split two texts into a list of strings. Reduce the texts to a string of + * hashes where each Unicode character represents one word. + * + * @param text1 First string. + * @param text2 Second string. + * @return An object containing the encoded text1, the encoded text2 and + * the List of unique strings. The zeroth element of the List of + * unique strings is intentionally blank. + */ + protected LinesToCharsResult diff_wordsToChars(String text1, String text2) { + List lineArray = new ArrayList(); + Map lineHash = new HashMap(); + // e.g. linearray[4] == "Hello\n" + // e.g. linehash.get("Hello\n") == 4 + + // "\x00" is a valid character, but various debuggers don't like it. + // So we'll insert a junk entry to avoid generating a null character. + lineArray.add(""); + + String chars1 = diff_wordsToCharsMunge(text1, lineArray, lineHash); + String chars2 = diff_wordsToCharsMunge(text2, lineArray, lineHash); + return new LinesToCharsResult(chars1, chars2, lineArray); + } + + /** + * Split a text into a list of strings. Reduce the texts to a string of + * hashes where each Unicode character represents one line. + * + * @param text String to encode. + * @param lineArray List of unique strings. + * @param lineHash Map of strings to indices. + * @return Encoded string. + */ + private String diff_linesToCharsMunge(String text, List lineArray, + Map lineHash) { + int lineStart = 0; + int lineEnd = -1; + String line; + StringBuilder chars = new StringBuilder(); + // Walk the text, pulling out a substring for each line. + // text.split('\n') would would temporarily double our memory footprint. + // Modifying text would create many large strings to garbage collect. + while (lineEnd < text.length() - 1) { + lineEnd = text.indexOf('\n', lineStart); + if (lineEnd == -1) { + lineEnd = text.length() - 1; + } + line = text.substring(lineStart, lineEnd + 1); + lineStart = lineEnd + 1; + + if (lineHash.containsKey(line)) { + chars.append(String.valueOf((char) (int) lineHash.get(line))); + } else { + lineArray.add(line); + lineHash.put(line, lineArray.size() - 1); + chars.append(String.valueOf((char) (lineArray.size() - 1))); + } + } + return chars.toString(); + } + + /** + * Split a text into a list of strings. Reduce the texts to a string of + * hashes where each Unicode character represents one word. + * + * @param text String to encode. + * @param lineArray List of unique strings. + * @param lineHash Map of strings to indices. + * @return Encoded string. + */ + private String diff_wordsToCharsMunge(String text, List lineArray, + Map lineHash) { + int lineStart = 0; + int lineEnd = -1; + String line; + StringBuilder chars = new StringBuilder(); + // Walk the text, pulling out a substring for each line. + // text.split('\n') would would temporarily double our memory footprint. + // Modifying text would create many large strings to garbage collect. + while (lineEnd < text.length() - 1) { + String patternStr = "[. :;\\[\\]\\{\\}\\(\\)\\+!?\\-]"; + Pattern pattern = Pattern.compile(patternStr); + Matcher matcher = pattern.matcher(text); + matcher.region(lineStart, text.length()); + + if (matcher.find()) { + lineEnd = matcher.start(); + } else + lineEnd = -1; + + if (lineEnd == -1) { + lineEnd = text.length() - 1; + } + line = text.substring(lineStart, lineEnd + 1); + lineStart = lineEnd + 1; + + if (lineHash.containsKey(line)) { + chars.append(String.valueOf((char) (int) lineHash.get(line))); + } else { + lineArray.add(line); + lineHash.put(line, lineArray.size() - 1); + chars.append(String.valueOf((char) (lineArray.size() - 1))); + } + } + return chars.toString(); + } + + /** + * Rehydrate the text in a diff from a string of line hashes to real lines of + * text. + * + * @param diffs LinkedList of Diff objects. + * @param lineArray List of unique strings. + */ + protected void diff_charsToLines(LinkedList diffs, + List lineArray) { + StringBuilder text; + for (Diff diff : diffs) { + text = new StringBuilder(); + for (int y = 0; y < diff.text.length(); y++) { + text.append(lineArray.get(diff.text.charAt(y))); + } + diff.text = text.toString(); + } + } + + /** + * Determine the common prefix of two strings + * + * @param text1 First string. + * @param text2 Second string. + * @return The number of characters common to the start of each string. + */ + public int diff_commonPrefix(String text1, String text2) { + // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + int n = Math.min(text1.length(), text2.length()); + for (int i = 0; i < n; i++) { + if (text1.charAt(i) != text2.charAt(i)) { + return i; + } + } + return n; + } + + /** + * Determine the common suffix of two strings + * + * @param text1 First string. + * @param text2 Second string. + * @return The number of characters common to the end of each string. + */ + public int diff_commonSuffix(String text1, String text2) { + // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + int text1_length = text1.length(); + int text2_length = text2.length(); + int n = Math.min(text1_length, text2_length); + for (int i = 1; i <= n; i++) { + if (text1.charAt(text1_length - i) != text2.charAt(text2_length - i)) { + return i - 1; + } + } + return n; + } + + /** + * Determine if the suffix of one string is the prefix of another. + * + * @param text1 First string. + * @param text2 Second string. + * @return The number of characters common to the end of the first + * string and the start of the second string. + */ + protected int diff_commonOverlap(String text1, String text2) { + // Cache the text lengths to prevent multiple calls. + int text1_length = text1.length(); + int text2_length = text2.length(); + // Eliminate the null case. + if (text1_length == 0 || text2_length == 0) { + return 0; + } + // Truncate the longer string. + if (text1_length > text2_length) { + text1 = text1.substring(text1_length - text2_length); + } else if (text1_length < text2_length) { + text2 = text2.substring(0, text1_length); + } + int text_length = Math.min(text1_length, text2_length); + // Quick check for the worst case. + if (text1.equals(text2)) { + return text_length; + } + + // Start by looking for a single character match + // and increase length until no match is found. + // Performance analysis: http://neil.fraser.name/news/2010/11/04/ + int best = 0; + int length = 1; + while (true) { + String pattern = text1.substring(text_length - length); + int found = text2.indexOf(pattern); + if (found == -1) { + return best; + } + length += found; + if (found == 0 || text1.substring(text_length - length).equals( + text2.substring(0, length))) { + best = length; + length++; + } + } + } + + /** + * Do the two texts share a substring which is at least half the length of + * the longer text? + * This speedup can produce non-minimal diffs. + * + * @param text1 First string. + * @param text2 Second string. + * @return Five element String array, containing the prefix of text1, the + * suffix of text1, the prefix of text2, the suffix of text2 and the + * common middle. Or null if there was no match. + */ + protected String[] diff_halfMatch(String text1, String text2) { + if (Diff_Timeout <= 0) { + // Don't risk returning a non-optimal diff if we have unlimited time. + return null; + } + String longtext = text1.length() > text2.length() ? text1 : text2; + String shorttext = text1.length() > text2.length() ? text2 : text1; + if (longtext.length() < 4 || shorttext.length() * 2 < longtext.length()) { + return null; // Pointless. + } + + // First check if the second quarter is the seed for a half-match. + String[] hm1 = diff_halfMatchI(longtext, shorttext, + (longtext.length() + 3) / 4); + // Check again based on the third quarter. + String[] hm2 = diff_halfMatchI(longtext, shorttext, + (longtext.length() + 1) / 2); + String[] hm; + if (hm1 == null && hm2 == null) { + return null; + } else if (hm2 == null) { + hm = hm1; + } else if (hm1 == null) { + hm = hm2; + } else { + // Both matched. Select the longest. + hm = hm1[4].length() > hm2[4].length() ? hm1 : hm2; + } + + // A half-match was found, sort out the return data. + if (text1.length() > text2.length()) { + return hm; + //return new String[]{hm[0], hm[1], hm[2], hm[3], hm[4]}; + } else { + return new String[]{hm[2], hm[3], hm[0], hm[1], hm[4]}; + } + } + + /** + * Does a substring of shorttext exist within longtext such that the + * substring is at least half the length of longtext? + * + * @param longtext Longer string. + * @param shorttext Shorter string. + * @param i Start index of quarter length substring within longtext. + * @return Five element String array, containing the prefix of longtext, the + * suffix of longtext, the prefix of shorttext, the suffix of shorttext + * and the common middle. Or null if there was no match. + */ + private String[] diff_halfMatchI(String longtext, String shorttext, int i) { + // Start with a 1/4 length substring at position i as a seed. + String seed = longtext.substring(i, i + longtext.length() / 4); + int j = -1; + String best_common = ""; + String best_longtext_a = "", best_longtext_b = ""; + String best_shorttext_a = "", best_shorttext_b = ""; + while ((j = shorttext.indexOf(seed, j + 1)) != -1) { + int prefixLength = diff_commonPrefix(longtext.substring(i), + shorttext.substring(j)); + int suffixLength = diff_commonSuffix(longtext.substring(0, i), + shorttext.substring(0, j)); + if (best_common.length() < suffixLength + prefixLength) { + best_common = shorttext.substring(j - suffixLength, j) + + shorttext.substring(j, j + prefixLength); + best_longtext_a = longtext.substring(0, i - suffixLength); + best_longtext_b = longtext.substring(i + prefixLength); + best_shorttext_a = shorttext.substring(0, j - suffixLength); + best_shorttext_b = shorttext.substring(j + prefixLength); + } + } + if (best_common.length() * 2 >= longtext.length()) { + return new String[]{best_longtext_a, best_longtext_b, + best_shorttext_a, best_shorttext_b, best_common}; + } else { + return null; + } + } + + /** + * Reduce the number of edits by eliminating semantically trivial equalities. + * + * @param diffs LinkedList of Diff objects. + */ + public void diff_cleanupSemantic(LinkedList diffs) { + if (diffs.isEmpty()) { + return; + } + boolean changes = false; + Stack equalities = new Stack(); // Stack of qualities. + String lastequality = null; // Always equal to equalities.lastElement().text + ListIterator pointer = diffs.listIterator(); + // Number of characters that changed prior to the equality. + int length_insertions1 = 0; + int length_deletions1 = 0; + // Number of characters that changed after the equality. + int length_insertions2 = 0; + int length_deletions2 = 0; + Diff thisDiff = pointer.next(); + while (thisDiff != null) { + if (thisDiff.operation == Operation.EQUAL) { + // Equality found. + equalities.push(thisDiff); + length_insertions1 = length_insertions2; + length_deletions1 = length_deletions2; + length_insertions2 = 0; + length_deletions2 = 0; + lastequality = thisDiff.text; + } else { + // An insertion or deletion. + if (thisDiff.operation == Operation.INSERT) { + length_insertions2 += thisDiff.text.length(); + } else { + length_deletions2 += thisDiff.text.length(); + } + // Eliminate an equality that is smaller or equal to the edits on both + // sides of it. + if (lastequality != null && (lastequality.length() + <= Math.max(length_insertions1, length_deletions1)) + && (lastequality.length() + <= Math.max(length_insertions2, length_deletions2))) { + //System.out.println("Splitting: '" + lastequality + "'"); + // Walk back to offending equality. + while (thisDiff != equalities.lastElement()) { + thisDiff = pointer.previous(); + } + pointer.next(); + + // Replace equality with a delete. + pointer.set(new Diff(Operation.DELETE, lastequality)); + // Insert a corresponding an insert. + pointer.add(new Diff(Operation.INSERT, lastequality)); + + equalities.pop(); // Throw away the equality we just deleted. + if (!equalities.empty()) { + // Throw away the previous equality (it needs to be reevaluated). + equalities.pop(); + } + if (equalities.empty()) { + // There are no previous equalities, walk back to the start. + while (pointer.hasPrevious()) { + pointer.previous(); + } + } else { + // There is a safe equality we can fall back to. + thisDiff = equalities.lastElement(); + while (thisDiff != pointer.previous()) { + // Intentionally empty loop. + } + } + + length_insertions1 = 0; // Reset the counters. + length_insertions2 = 0; + length_deletions1 = 0; + length_deletions2 = 0; + lastequality = null; + changes = true; + } + } + thisDiff = pointer.hasNext() ? pointer.next() : null; + } + + // Normalize the diff. + if (changes) { + diff_cleanupMerge(diffs); + } + diff_cleanupSemanticLossless(diffs); + + // Find any overlaps between deletions and insertions. + // e.g: abcxxxxxxdef + // -> abcxxxdef + // e.g: xxxabcdefxxx + // -> defxxxabc + // Only extract an overlap if it is as big as the edit ahead or behind it. + pointer = diffs.listIterator(); + Diff prevDiff = null; + thisDiff = null; + if (pointer.hasNext()) { + prevDiff = pointer.next(); + if (pointer.hasNext()) { + thisDiff = pointer.next(); + } + } + while (thisDiff != null) { + if (prevDiff.operation == Operation.DELETE && + thisDiff.operation == Operation.INSERT) { + String deletion = prevDiff.text; + String insertion = thisDiff.text; + int overlap_length1 = this.diff_commonOverlap(deletion, insertion); + int overlap_length2 = this.diff_commonOverlap(insertion, deletion); + if (overlap_length1 >= overlap_length2) { + if (overlap_length1 >= deletion.length() / 2.0 || + overlap_length1 >= insertion.length() / 2.0) { + // Overlap found. Insert an equality and trim the surrounding edits. + pointer.previous(); + pointer.add(new Diff(Operation.EQUAL, + insertion.substring(0, overlap_length1))); + prevDiff.text = + deletion.substring(0, deletion.length() - overlap_length1); + thisDiff.text = insertion.substring(overlap_length1); + // pointer.add inserts the element before the cursor, so there is + // no need to step past the new element. + } + } else { + if (overlap_length2 >= deletion.length() / 2.0 || + overlap_length2 >= insertion.length() / 2.0) { + // Reverse overlap found. + // Insert an equality and swap and trim the surrounding edits. + pointer.previous(); + pointer.add(new Diff(Operation.EQUAL, + deletion.substring(0, overlap_length2))); + prevDiff.operation = Operation.INSERT; + prevDiff.text = + insertion.substring(0, insertion.length() - overlap_length2); + thisDiff.operation = Operation.DELETE; + thisDiff.text = deletion.substring(overlap_length2); + // pointer.add inserts the element before the cursor, so there is + // no need to step past the new element. + } + } + thisDiff = pointer.hasNext() ? pointer.next() : null; + } + prevDiff = thisDiff; + thisDiff = pointer.hasNext() ? pointer.next() : null; + } + } + + /** + * Look for single edits surrounded on both sides by equalities + * which can be shifted sideways to align the edit to a word boundary. + * e.g: The cat came. -> The cat came. + * + * @param diffs LinkedList of Diff objects. + */ + public void diff_cleanupSemanticLossless(LinkedList diffs) { + String equality1, edit, equality2; + String commonString; + int commonOffset; + int score, bestScore; + String bestEquality1, bestEdit, bestEquality2; + // Create a new iterator at the start. + ListIterator pointer = diffs.listIterator(); + Diff prevDiff = pointer.hasNext() ? pointer.next() : null; + Diff thisDiff = pointer.hasNext() ? pointer.next() : null; + Diff nextDiff = pointer.hasNext() ? pointer.next() : null; + // Intentionally ignore the first and last element (don't need checking). + while (nextDiff != null) { + if (prevDiff.operation == Operation.EQUAL && + nextDiff.operation == Operation.EQUAL) { + // This is a single edit surrounded by equalities. + equality1 = prevDiff.text; + edit = thisDiff.text; + equality2 = nextDiff.text; + + // First, shift the edit as far left as possible. + commonOffset = diff_commonSuffix(equality1, edit); + if (commonOffset != 0) { + commonString = edit.substring(edit.length() - commonOffset); + equality1 = equality1.substring(0, equality1.length() - commonOffset); + edit = commonString + edit.substring(0, edit.length() - commonOffset); + equality2 = commonString + equality2; + } + + // Second, step character by character right, looking for the best fit. + bestEquality1 = equality1; + bestEdit = edit; + bestEquality2 = equality2; + bestScore = diff_cleanupSemanticScore(equality1, edit) + + diff_cleanupSemanticScore(edit, equality2); + while (edit.length() != 0 && equality2.length() != 0 + && edit.charAt(0) == equality2.charAt(0)) { + equality1 += edit.charAt(0); + edit = edit.substring(1) + equality2.charAt(0); + equality2 = equality2.substring(1); + score = diff_cleanupSemanticScore(equality1, edit) + + diff_cleanupSemanticScore(edit, equality2); + // The >= encourages trailing rather than leading whitespace on edits. + if (score >= bestScore) { + bestScore = score; + bestEquality1 = equality1; + bestEdit = edit; + bestEquality2 = equality2; + } + } + + if (!prevDiff.text.equals(bestEquality1)) { + // We have an improvement, save it back to the diff. + if (bestEquality1.length() != 0) { + prevDiff.text = bestEquality1; + } else { + pointer.previous(); // Walk past nextDiff. + pointer.previous(); // Walk past thisDiff. + pointer.previous(); // Walk past prevDiff. + pointer.remove(); // Delete prevDiff. + pointer.next(); // Walk past thisDiff. + pointer.next(); // Walk past nextDiff. + } + thisDiff.text = bestEdit; + if (bestEquality2.length() != 0) { + nextDiff.text = bestEquality2; + } else { + pointer.remove(); // Delete nextDiff. + nextDiff = thisDiff; + thisDiff = prevDiff; + } + } + } + prevDiff = thisDiff; + thisDiff = nextDiff; + nextDiff = pointer.hasNext() ? pointer.next() : null; + } + } + + /** + * Given two strings, compute a score representing whether the internal + * boundary falls on logical boundaries. + * Scores range from 6 (best) to 0 (worst). + * + * @param one First string. + * @param two Second string. + * @return The score. + */ + private int diff_cleanupSemanticScore(String one, String two) { + if (one.length() == 0 || two.length() == 0) { + // Edges are the best. + return 6; + } + + // Each port of this function behaves slightly differently due to + // subtle differences in each language's definition of things like + // 'whitespace'. Since this function's purpose is largely cosmetic, + // the choice has been made to use each language's native features + // rather than force total conformity. + char char1 = one.charAt(one.length() - 1); + char char2 = two.charAt(0); + boolean nonAlphaNumeric1 = !Character.isLetterOrDigit(char1); + boolean nonAlphaNumeric2 = !Character.isLetterOrDigit(char2); + boolean whitespace1 = nonAlphaNumeric1 && Character.isWhitespace(char1); + boolean whitespace2 = nonAlphaNumeric2 && Character.isWhitespace(char2); + boolean lineBreak1 = whitespace1 + && Character.getType(char1) == Character.CONTROL; + boolean lineBreak2 = whitespace2 + && Character.getType(char2) == Character.CONTROL; + boolean blankLine1 = lineBreak1 && BLANKLINEEND.matcher(one).find(); + boolean blankLine2 = lineBreak2 && BLANKLINESTART.matcher(two).find(); + + if (blankLine1 || blankLine2) { + // Five points for blank lines. + return 5; + } else if (lineBreak1 || lineBreak2) { + // Four points for line breaks. + return 4; + } else if (nonAlphaNumeric1 && !whitespace1 && whitespace2) { + // Three points for end of sentences. + return 3; + } else if (whitespace1 || whitespace2) { + // Two points for whitespace. + return 2; + } else if (nonAlphaNumeric1 || nonAlphaNumeric2) { + // One point for non-alphanumeric. + return 1; + } + return 0; + } + + /** + * Reduce the number of edits by eliminating operationally trivial equalities. + * + * @param diffs LinkedList of Diff objects. + */ + public void diff_cleanupEfficiency(LinkedList diffs) { + if (diffs.isEmpty()) { + return; + } + boolean changes = false; + Stack equalities = new Stack(); // Stack of equalities. + String lastequality = null; // Always equal to equalities.lastElement().text + ListIterator pointer = diffs.listIterator(); + // Is there an insertion operation before the last equality. + boolean pre_ins = false; + // Is there a deletion operation before the last equality. + boolean pre_del = false; + // Is there an insertion operation after the last equality. + boolean post_ins = false; + // Is there a deletion operation after the last equality. + boolean post_del = false; + Diff thisDiff = pointer.next(); + Diff safeDiff = thisDiff; // The last Diff that is known to be unsplitable. + while (thisDiff != null) { + if (thisDiff.operation == Operation.EQUAL) { + // Equality found. + if (thisDiff.text.length() < Diff_EditCost && (post_ins || post_del)) { + // Candidate found. + equalities.push(thisDiff); + pre_ins = post_ins; + pre_del = post_del; + lastequality = thisDiff.text; + } else { + // Not a candidate, and can never become one. + equalities.clear(); + lastequality = null; + safeDiff = thisDiff; + } + post_ins = post_del = false; + } else { + // An insertion or deletion. + if (thisDiff.operation == Operation.DELETE) { + post_del = true; + } else { + post_ins = true; + } + /* + * Five types to be split: + * ABXYCD + * AXCD + * ABXC + * AXCD + * ABXC + */ + if (lastequality != null + && ((pre_ins && pre_del && post_ins && post_del) + || ((lastequality.length() < Diff_EditCost / 2) + && ((pre_ins ? 1 : 0) + (pre_del ? 1 : 0) + + (post_ins ? 1 : 0) + (post_del ? 1 : 0)) == 3))) { + //System.out.println("Splitting: '" + lastequality + "'"); + // Walk back to offending equality. + while (thisDiff != equalities.lastElement()) { + thisDiff = pointer.previous(); + } + pointer.next(); + + // Replace equality with a delete. + pointer.set(new Diff(Operation.DELETE, lastequality)); + // Insert a corresponding an insert. + pointer.add(thisDiff = new Diff(Operation.INSERT, lastequality)); + + equalities.pop(); // Throw away the equality we just deleted. + lastequality = null; + if (pre_ins && pre_del) { + // No changes made which could affect previous entry, keep going. + post_ins = post_del = true; + equalities.clear(); + safeDiff = thisDiff; + } else { + if (!equalities.empty()) { + // Throw away the previous equality (it needs to be reevaluated). + equalities.pop(); + } + if (equalities.empty()) { + // There are no previous questionable equalities, + // walk back to the last known safe diff. + thisDiff = safeDiff; + } else { + // There is an equality we can fall back to. + thisDiff = equalities.lastElement(); + } + while (thisDiff != pointer.previous()) { + // Intentionally empty loop. + } + post_ins = post_del = false; + } + + changes = true; + } + } + thisDiff = pointer.hasNext() ? pointer.next() : null; + } + + if (changes) { + diff_cleanupMerge(diffs); + } + } + + /** + * Reorder and merge like edit sections. Merge equalities. + * Any edit section can move as long as it doesn't cross an equality. + * + * @param diffs LinkedList of Diff objects. + */ + public void diff_cleanupMerge(LinkedList diffs) { + diffs.add(new Diff(Operation.EQUAL, "")); // Add a dummy entry at the end. + ListIterator pointer = diffs.listIterator(); + int count_delete = 0; + int count_insert = 0; + String text_delete = ""; + String text_insert = ""; + Diff thisDiff = pointer.next(); + Diff prevEqual = null; + int commonlength; + while (thisDiff != null) { + switch (thisDiff.operation) { + case INSERT: + count_insert++; + text_insert += thisDiff.text; + prevEqual = null; + break; + case DELETE: + count_delete++; + text_delete += thisDiff.text; + prevEqual = null; + break; + case EQUAL: + if (count_delete + count_insert > 1) { + boolean both_types = count_delete != 0 && count_insert != 0; + // Delete the offending records. + pointer.previous(); // Reverse direction. + while (count_delete-- > 0) { + pointer.previous(); + pointer.remove(); + } + while (count_insert-- > 0) { + pointer.previous(); + pointer.remove(); + } + if (both_types) { + // Factor out any common prefixies. + commonlength = diff_commonPrefix(text_insert, text_delete); + if (commonlength != 0) { + if (pointer.hasPrevious()) { + thisDiff = pointer.previous(); + assert thisDiff.operation == Operation.EQUAL + : "Previous diff should have been an equality."; + thisDiff.text += text_insert.substring(0, commonlength); + pointer.next(); + } else { + pointer.add(new Diff(Operation.EQUAL, + text_insert.substring(0, commonlength))); + } + text_insert = text_insert.substring(commonlength); + text_delete = text_delete.substring(commonlength); + } + // Factor out any common suffixies. + commonlength = diff_commonSuffix(text_insert, text_delete); + if (commonlength != 0) { + thisDiff = pointer.next(); + thisDiff.text = text_insert.substring(text_insert.length() + - commonlength) + thisDiff.text; + text_insert = text_insert.substring(0, text_insert.length() + - commonlength); + text_delete = text_delete.substring(0, text_delete.length() + - commonlength); + pointer.previous(); + } + } + // Insert the merged records. + if (text_delete.length() != 0) { + pointer.add(new Diff(Operation.DELETE, text_delete)); + } + if (text_insert.length() != 0) { + pointer.add(new Diff(Operation.INSERT, text_insert)); + } + // Step forward to the equality. + thisDiff = pointer.hasNext() ? pointer.next() : null; + } else if (prevEqual != null) { + // Merge this equality with the previous one. + prevEqual.text += thisDiff.text; + pointer.remove(); + thisDiff = pointer.previous(); + pointer.next(); // Forward direction + } + count_insert = 0; + count_delete = 0; + text_delete = ""; + text_insert = ""; + prevEqual = thisDiff; + break; + } + thisDiff = pointer.hasNext() ? pointer.next() : null; + } + if (diffs.getLast().text.length() == 0) { + diffs.removeLast(); // Remove the dummy entry at the end. + } + + /* + * Second pass: look for single edits surrounded on both sides by equalities + * which can be shifted sideways to eliminate an equality. + * e.g: ABAC -> ABAC + */ + boolean changes = false; + // Create a new iterator at the start. + // (As opposed to walking the current one back.) + pointer = diffs.listIterator(); + Diff prevDiff = pointer.hasNext() ? pointer.next() : null; + thisDiff = pointer.hasNext() ? pointer.next() : null; + Diff nextDiff = pointer.hasNext() ? pointer.next() : null; + // Intentionally ignore the first and last element (don't need checking). + while (nextDiff != null) { + if (prevDiff.operation == Operation.EQUAL && + nextDiff.operation == Operation.EQUAL) { + // This is a single edit surrounded by equalities. + if (thisDiff.text.endsWith(prevDiff.text)) { + // Shift the edit over the previous equality. + thisDiff.text = prevDiff.text + + thisDiff.text.substring(0, thisDiff.text.length() + - prevDiff.text.length()); + nextDiff.text = prevDiff.text + nextDiff.text; + pointer.previous(); // Walk past nextDiff. + pointer.previous(); // Walk past thisDiff. + pointer.previous(); // Walk past prevDiff. + pointer.remove(); // Delete prevDiff. + pointer.next(); // Walk past thisDiff. + thisDiff = pointer.next(); // Walk past nextDiff. + nextDiff = pointer.hasNext() ? pointer.next() : null; + changes = true; + } else if (thisDiff.text.startsWith(nextDiff.text)) { + // Shift the edit over the next equality. + prevDiff.text += nextDiff.text; + thisDiff.text = thisDiff.text.substring(nextDiff.text.length()) + + nextDiff.text; + pointer.remove(); // Delete nextDiff. + nextDiff = pointer.hasNext() ? pointer.next() : null; + changes = true; + } + } + prevDiff = thisDiff; + thisDiff = nextDiff; + nextDiff = pointer.hasNext() ? pointer.next() : null; + } + // If shifts were made, the diff needs reordering and another shift sweep. + if (changes) { + diff_cleanupMerge(diffs); + } + } + + /** + * loc is a location in text1, compute and return the equivalent location in + * text2. + * e.g. "The cat" vs "The big cat", 1->1, 5->8 + * + * @param diffs LinkedList of Diff objects. + * @param loc Location within text1. + * @return Location within text2. + */ + public int diff_xIndex(LinkedList diffs, int loc) { + int chars1 = 0; + int chars2 = 0; + int last_chars1 = 0; + int last_chars2 = 0; + Diff lastDiff = null; + for (Diff aDiff : diffs) { + if (aDiff.operation != Operation.INSERT) { + // Equality or deletion. + chars1 += aDiff.text.length(); + } + if (aDiff.operation != Operation.DELETE) { + // Equality or insertion. + chars2 += aDiff.text.length(); + } + if (chars1 > loc) { + // Overshot the location. + lastDiff = aDiff; + break; + } + last_chars1 = chars1; + last_chars2 = chars2; + } + if (lastDiff != null && lastDiff.operation == Operation.DELETE) { + // The location was deleted. + return last_chars2; + } + // Add the remaining character length. + return last_chars2 + (loc - last_chars1); + } + + /** + * Convert a Diff list into a pretty HTML report. + * + * @param diffs LinkedList of Diff objects. + * @return HTML representation. + number of equal words in an array + * where first element is HTML representation and second + * is number of Equal words. + */ + public String[] diff_prettyHtml(LinkedList diffs) { + StringBuilder html = new StringBuilder(); + int numEqual = 0; + for (Diff aDiff : diffs) { + String text = aDiff.text.replace("&", "&").replace("<", "<") + .replace(">", ">").replace("\n", "¶
"); + switch (aDiff.operation) { + case INSERT: + html.append("").append(text) + .append(""); + break; + case DELETE: + html.append("").append(text) + .append(""); + break; + case EQUAL: + html.append("").append(text).append(""); + numEqual += text.split(" ").length; + break; + } + } + return new String[]{html.toString(), String.valueOf(numEqual)}; + } + + /** + * Compute and return the source text (all equalities and deletions). + * + * @param diffs LinkedList of Diff objects. + * @return Source text. + */ + public String diff_text1(LinkedList diffs) { + StringBuilder text = new StringBuilder(); + for (Diff aDiff : diffs) { + if (aDiff.operation != Operation.INSERT) { + text.append(aDiff.text); + } + } + return text.toString(); + } + + /** + * Compute and return the destination text (all equalities and insertions). + * + * @param diffs LinkedList of Diff objects. + * @return Destination text. + */ + public String diff_text2(LinkedList diffs) { + StringBuilder text = new StringBuilder(); + for (Diff aDiff : diffs) { + if (aDiff.operation != Operation.DELETE) { + text.append(aDiff.text); + } + } + return text.toString(); + } + + /** + * Compute the Levenshtein distance; the number of inserted, deleted or + * substituted characters. + * + * @param diffs LinkedList of Diff objects. + * @return Number of changes. + */ + public int diff_levenshtein(LinkedList diffs) { + int levenshtein = 0; + int insertions = 0; + int deletions = 0; + for (Diff aDiff : diffs) { + switch (aDiff.operation) { + case INSERT: + insertions += aDiff.text.length(); + break; + case DELETE: + deletions += aDiff.text.length(); + break; + case EQUAL: + // A deletion and an insertion is one substitution. + levenshtein += Math.max(insertions, deletions); + insertions = 0; + deletions = 0; + break; + } + } + levenshtein += Math.max(insertions, deletions); + return levenshtein; + } + + /** + * Crush the diff into an encoded string which describes the operations + * required to transform text1 into text2. + * E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'. + * Operations are tab-separated. Inserted text is escaped using %xx notation. + * + * @param diffs Array of Diff objects. + * @return Delta text. + */ + public String diff_toDelta(LinkedList diffs) { + StringBuilder text = new StringBuilder(); + for (Diff aDiff : diffs) { + switch (aDiff.operation) { + case INSERT: + try { + text.append("+").append(URLEncoder.encode(aDiff.text, "UTF-8") + .replace('+', ' ')).append("\t"); + } catch (UnsupportedEncodingException e) { + // Not likely on modern system. + throw new Error("This system does not support UTF-8.", e); + } + break; + case DELETE: + text.append("-").append(aDiff.text.length()).append("\t"); + break; + case EQUAL: + text.append("=").append(aDiff.text.length()).append("\t"); + break; + } + } + String delta = text.toString(); + if (delta.length() != 0) { + // Strip off trailing tab character. + delta = delta.substring(0, delta.length() - 1); + delta = unescapeForEncodeUriCompatability(delta); + } + return delta; + } + + /** + * Given the original text1, and an encoded string which describes the + * operations required to transform text1 into text2, compute the full diff. + * + * @param text1 Source string for the diff. + * @param delta Delta text. + * @return Array of Diff objects or null if invalid. + * @throws IllegalArgumentException If invalid input. + */ + public LinkedList diff_fromDelta(String text1, String delta) + throws IllegalArgumentException { + LinkedList diffs = new LinkedList(); + int pointer = 0; // Cursor in text1 + String[] tokens = delta.split("\t"); + for (String token : tokens) { + if (token.length() == 0) { + // Blank tokens are ok (from a trailing \t). + continue; + } + // Each token begins with a one character parameter which specifies the + // operation of this token (delete, insert, equality). + String param = token.substring(1); + switch (token.charAt(0)) { + case '+': + // decode would change all "+" to " " + param = param.replace("+", "%2B"); + try { + param = URLDecoder.decode(param, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // Not likely on modern system. + throw new Error("This system does not support UTF-8.", e); + } catch (IllegalArgumentException e) { + // Malformed URI sequence. + throw new IllegalArgumentException( + "Illegal escape in diff_fromDelta: " + param, e); + } + diffs.add(new Diff(Operation.INSERT, param)); + break; + case '-': + // Fall through. + case '=': + int n; + try { + n = Integer.parseInt(param); + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "Invalid number in diff_fromDelta: " + param, e); + } + if (n < 0) { + throw new IllegalArgumentException( + "Negative number in diff_fromDelta: " + param); + } + String text; + try { + text = text1.substring(pointer, pointer += n); + } catch (StringIndexOutOfBoundsException e) { + throw new IllegalArgumentException("Delta length (" + pointer + + ") larger than source text length (" + text1.length() + + ").", e); + } + if (token.charAt(0) == '=') { + diffs.add(new Diff(Operation.EQUAL, text)); + } else { + diffs.add(new Diff(Operation.DELETE, text)); + } + break; + default: + // Anything else is an error. + throw new IllegalArgumentException( + "Invalid diff operation in diff_fromDelta: " + token.charAt(0)); + } + } + if (pointer != text1.length()) { + throw new IllegalArgumentException("Delta length (" + pointer + + ") smaller than source text length (" + text1.length() + ")."); + } + return diffs; + } + + /** + * Locate the best instance of 'pattern' in 'text' near 'loc'. + * Returns -1 if no match found. + * + * @param text The text to search. + * @param pattern The pattern to search for. + * @param loc The location to search around. + * @return Best match index or -1. + */ + public int match_main(String text, String pattern, int loc) { + // Check for null inputs. + if (text == null || pattern == null) { + throw new IllegalArgumentException("Null inputs. (match_main)"); + } + + loc = Math.max(0, Math.min(loc, text.length())); + if (text.equals(pattern)) { + // Shortcut (potentially not guaranteed by the algorithm) + return 0; + } else if (text.length() == 0) { + // Nothing to match. + return -1; + } else if (loc + pattern.length() <= text.length() + && text.substring(loc, loc + pattern.length()).equals(pattern)) { + // Perfect match at the perfect spot! (Includes case of null pattern) + return loc; + } else { + // Do a fuzzy compare. + return match_bitap(text, pattern, loc); + } + } + + + // MATCH FUNCTIONS + + /** + * Locate the best instance of 'pattern' in 'text' near 'loc' using the + * Bitap algorithm. Returns -1 if no match found. + * + * @param text The text to search. + * @param pattern The pattern to search for. + * @param loc The location to search around. + * @return Best match index or -1. + */ + protected int match_bitap(String text, String pattern, int loc) { + assert (Match_MaxBits == 0 || pattern.length() <= Match_MaxBits) + : "Pattern too long for this application."; + + // Initialise the alphabet. + Map s = match_alphabet(pattern); + + // Highest score beyond which we give up. + double score_threshold = Match_Threshold; + // Is there a nearby exact match? (speedup) + int best_loc = text.indexOf(pattern, loc); + if (best_loc != -1) { + score_threshold = Math.min(match_bitapScore(0, best_loc, loc, pattern), + score_threshold); + // What about in the other direction? (speedup) + best_loc = text.lastIndexOf(pattern, loc + pattern.length()); + if (best_loc != -1) { + score_threshold = Math.min(match_bitapScore(0, best_loc, loc, pattern), + score_threshold); + } + } + + // Initialise the bit arrays. + int matchmask = 1 << (pattern.length() - 1); + best_loc = -1; + + int bin_min, bin_mid; + int bin_max = pattern.length() + text.length(); + // Empty initialization added to appease Java compiler. + int[] last_rd = new int[0]; + for (int d = 0; d < pattern.length(); d++) { + // Scan for the best match; each iteration allows for one more error. + // Run a binary search to determine how far from 'loc' we can stray at + // this error level. + bin_min = 0; + bin_mid = bin_max; + while (bin_min < bin_mid) { + if (match_bitapScore(d, loc + bin_mid, loc, pattern) + <= score_threshold) { + bin_min = bin_mid; + } else { + bin_max = bin_mid; + } + bin_mid = (bin_max - bin_min) / 2 + bin_min; + } + // Use the result from this iteration as the maximum for the next. + bin_max = bin_mid; + int start = Math.max(1, loc - bin_mid + 1); + int finish = Math.min(loc + bin_mid, text.length()) + pattern.length(); + + int[] rd = new int[finish + 2]; + rd[finish + 1] = (1 << d) - 1; + for (int j = finish; j >= start; j--) { + int charMatch; + if (text.length() <= j - 1 || !s.containsKey(text.charAt(j - 1))) { + // Out of range. + charMatch = 0; + } else { + charMatch = s.get(text.charAt(j - 1)); + } + if (d == 0) { + // First pass: exact match. + rd[j] = ((rd[j + 1] << 1) | 1) & charMatch; + } else { + // Subsequent passes: fuzzy match. + rd[j] = (((rd[j + 1] << 1) | 1) & charMatch) + | (((last_rd[j + 1] | last_rd[j]) << 1) | 1) | last_rd[j + 1]; + } + if ((rd[j] & matchmask) != 0) { + double score = match_bitapScore(d, j - 1, loc, pattern); + // This match will almost certainly be better than any existing + // match. But check anyway. + if (score <= score_threshold) { + // Told you so. + score_threshold = score; + best_loc = j - 1; + if (best_loc > loc) { + // When passing loc, don't exceed our current distance from loc. + start = Math.max(1, 2 * loc - best_loc); + } else { + // Already passed loc, downhill from here on in. + break; + } + } + } + } + if (match_bitapScore(d + 1, loc, loc, pattern) > score_threshold) { + // No hope for a (better) match at greater error levels. + break; + } + last_rd = rd; + } + return best_loc; + } + + /** + * Compute and return the score for a match with e errors and x location. + * + * @param e Number of errors in match. + * @param x Location of match. + * @param loc Expected location of match. + * @param pattern Pattern being sought. + * @return Overall score for match (0.0 = good, 1.0 = bad). + */ + private double match_bitapScore(int e, int x, int loc, String pattern) { + float accuracy = (float) e / pattern.length(); + int proximity = Math.abs(loc - x); + if (Match_Distance == 0) { + // Dodge divide by zero error. + return proximity == 0 ? accuracy : 1.0; + } + return accuracy + (proximity / (float) Match_Distance); + } + + /** + * Initialise the alphabet for the Bitap algorithm. + * + * @param pattern The text to encode. + * @return Hash of character locations. + */ + protected Map match_alphabet(String pattern) { + Map s = new HashMap(); + char[] char_pattern = pattern.toCharArray(); + for (char c : char_pattern) { + s.put(c, 0); + } + int i = 0; + for (char c : char_pattern) { + s.put(c, s.get(c) | (1 << (pattern.length() - i - 1))); + i++; + } + return s; + } + + /** + * Increase the context until it is unique, + * but don't let the pattern expand beyond Match_MaxBits. + * + * @param patch The patch to grow. + * @param text Source text. + */ + protected void patch_addContext(Patch patch, String text) { + if (text.length() == 0) { + return; + } + String pattern = text.substring(patch.start2, patch.start2 + patch.length1); + int padding = 0; + + // Look for the first and last matches of pattern in text. If two different + // matches are found, increase the pattern length. + while (text.indexOf(pattern) != text.lastIndexOf(pattern) + && pattern.length() < Match_MaxBits - Patch_Margin - Patch_Margin) { + padding += Patch_Margin; + pattern = text.substring(Math.max(0, patch.start2 - padding), + Math.min(text.length(), patch.start2 + patch.length1 + padding)); + } + // Add one chunk for good luck. + padding += Patch_Margin; + + // Add the prefix. + String prefix = text.substring(Math.max(0, patch.start2 - padding), + patch.start2); + if (prefix.length() != 0) { + patch.diffs.addFirst(new Diff(Operation.EQUAL, prefix)); + } + // Add the suffix. + String suffix = text.substring(patch.start2 + patch.length1, + Math.min(text.length(), patch.start2 + patch.length1 + padding)); + if (suffix.length() != 0) { + patch.diffs.addLast(new Diff(Operation.EQUAL, suffix)); + } + + // Roll back the start points. + patch.start1 -= prefix.length(); + patch.start2 -= prefix.length(); + // Extend the lengths. + patch.length1 += prefix.length() + suffix.length(); + patch.length2 += prefix.length() + suffix.length(); + } + + + // PATCH FUNCTIONS + + /** + * Compute a list of patches to turn text1 into text2. + * A set of diffs will be computed. + * + * @param text1 Old text. + * @param text2 New text. + * @return LinkedList of Patch objects. + */ + public LinkedList patch_make(String text1, String text2) { + if (text1 == null || text2 == null) { + throw new IllegalArgumentException("Null inputs. (patch_make)"); + } + // No diffs provided, compute our own. + LinkedList diffs = diff_main(text1, text2, true); + if (diffs.size() > 2) { + diff_cleanupSemantic(diffs); + diff_cleanupEfficiency(diffs); + } + return patch_make(text1, diffs); + } + + /** + * Compute a list of patches to turn text1 into text2. + * text1 will be derived from the provided diffs. + * + * @param diffs Array of Diff objects for text1 to text2. + * @return LinkedList of Patch objects. + */ + public LinkedList patch_make(LinkedList diffs) { + if (diffs == null) { + throw new IllegalArgumentException("Null inputs. (patch_make)"); + } + // No origin string provided, compute our own. + String text1 = diff_text1(diffs); + return patch_make(text1, diffs); + } + + /** + * Compute a list of patches to turn text1 into text2. + * text2 is ignored, diffs are the delta between text1 and text2. + * + * @param text1 Old text + * @param text2 Ignored. + * @param diffs Array of Diff objects for text1 to text2. + * @return LinkedList of Patch objects. + * @deprecated Prefer patch_make(String text1, LinkedList diffs). + */ + public LinkedList patch_make(String text1, String text2, + LinkedList diffs) { + return patch_make(text1, diffs); + } + + /** + * Compute a list of patches to turn text1 into text2. + * text2 is not provided, diffs are the delta between text1 and text2. + * + * @param text1 Old text. + * @param diffs Array of Diff objects for text1 to text2. + * @return LinkedList of Patch objects. + */ + public LinkedList patch_make(String text1, LinkedList diffs) { + if (text1 == null || diffs == null) { + throw new IllegalArgumentException("Null inputs. (patch_make)"); + } + + LinkedList patches = new LinkedList(); + if (diffs.isEmpty()) { + return patches; // Get rid of the null case. + } + Patch patch = new Patch(); + int char_count1 = 0; // Number of characters into the text1 string. + int char_count2 = 0; // Number of characters into the text2 string. + // Start with text1 (prepatch_text) and apply the diffs until we arrive at + // text2 (postpatch_text). We recreate the patches one by one to determine + // context info. + String prepatch_text = text1; + String postpatch_text = text1; + for (Diff aDiff : diffs) { + if (patch.diffs.isEmpty() && aDiff.operation != Operation.EQUAL) { + // A new patch starts here. + patch.start1 = char_count1; + patch.start2 = char_count2; + } + + switch (aDiff.operation) { + case INSERT: + patch.diffs.add(aDiff); + patch.length2 += aDiff.text.length(); + postpatch_text = postpatch_text.substring(0, char_count2) + + aDiff.text + postpatch_text.substring(char_count2); + break; + case DELETE: + patch.length1 += aDiff.text.length(); + patch.diffs.add(aDiff); + postpatch_text = postpatch_text.substring(0, char_count2) + + postpatch_text.substring(char_count2 + aDiff.text.length()); + break; + case EQUAL: + if (aDiff.text.length() <= 2 * Patch_Margin + && !patch.diffs.isEmpty() && aDiff != diffs.getLast()) { + // Small equality inside a patch. + patch.diffs.add(aDiff); + patch.length1 += aDiff.text.length(); + patch.length2 += aDiff.text.length(); + } + + if (aDiff.text.length() >= 2 * Patch_Margin) { + // Time for a new patch. + if (!patch.diffs.isEmpty()) { + patch_addContext(patch, prepatch_text); + patches.add(patch); + patch = new Patch(); + // Unlike Unidiff, our patch lists have a rolling context. + // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff + // Update prepatch text & pos to reflect the application of the + // just completed patch. + prepatch_text = postpatch_text; + char_count1 = char_count2; + } + } + break; + } + + // Update the current character count. + if (aDiff.operation != Operation.INSERT) { + char_count1 += aDiff.text.length(); + } + if (aDiff.operation != Operation.DELETE) { + char_count2 += aDiff.text.length(); + } + } + // Pick up the leftover patch if not empty. + if (!patch.diffs.isEmpty()) { + patch_addContext(patch, prepatch_text); + patches.add(patch); + } + + return patches; + } + + /** + * Given an array of patches, return another array that is identical. + * + * @param patches Array of Patch objects. + * @return Array of Patch objects. + */ + public LinkedList patch_deepCopy(LinkedList patches) { + LinkedList patchesCopy = new LinkedList(); + for (Patch aPatch : patches) { + Patch patchCopy = new Patch(); + for (Diff aDiff : aPatch.diffs) { + Diff diffCopy = new Diff(aDiff.operation, aDiff.text); + patchCopy.diffs.add(diffCopy); + } + patchCopy.start1 = aPatch.start1; + patchCopy.start2 = aPatch.start2; + patchCopy.length1 = aPatch.length1; + patchCopy.length2 = aPatch.length2; + patchesCopy.add(patchCopy); + } + return patchesCopy; + } + + /** + * Merge a set of patches onto the text. Return a patched text, as well + * as an array of true/false values indicating which patches were applied. + * + * @param patches Array of Patch objects + * @param text Old text. + * @return Two element Object array, containing the new text and an array of + * boolean values. + */ + public Object[] patch_apply(LinkedList patches, String text) { + if (patches.isEmpty()) { + return new Object[]{text, new boolean[0]}; + } + + // Deep copy the patches so that no changes are made to originals. + patches = patch_deepCopy(patches); + + String nullPadding = patch_addPadding(patches); + text = nullPadding + text + nullPadding; + patch_splitMax(patches); + + int x = 0; + // delta keeps track of the offset between the expected and actual location + // of the previous patch. If there are patches expected at positions 10 and + // 20, but the first patch was found at 12, delta is 2 and the second patch + // has an effective expected position of 22. + int delta = 0; + boolean[] results = new boolean[patches.size()]; + for (Patch aPatch : patches) { + int expected_loc = aPatch.start2 + delta; + String text1 = diff_text1(aPatch.diffs); + int start_loc; + int end_loc = -1; + if (text1.length() > this.Match_MaxBits) { + // patch_splitMax will only provide an oversized pattern in the case of + // a monster delete. + start_loc = match_main(text, + text1.substring(0, this.Match_MaxBits), expected_loc); + if (start_loc != -1) { + end_loc = match_main(text, + text1.substring(text1.length() - this.Match_MaxBits), + expected_loc + text1.length() - this.Match_MaxBits); + if (end_loc == -1 || start_loc >= end_loc) { + // Can't find valid trailing context. Drop this patch. + start_loc = -1; + } + } + } else { + start_loc = match_main(text, text1, expected_loc); + } + if (start_loc == -1) { + // No match found. :( + results[x] = false; + // Subtract the delta for this failed patch from subsequent patches. + delta -= aPatch.length2 - aPatch.length1; + } else { + // Found a match. :) + results[x] = true; + delta = start_loc - expected_loc; + String text2; + if (end_loc == -1) { + text2 = text.substring(start_loc, + Math.min(start_loc + text1.length(), text.length())); + } else { + text2 = text.substring(start_loc, + Math.min(end_loc + this.Match_MaxBits, text.length())); + } + if (text1.equals(text2)) { + // Perfect match, just shove the replacement text in. + text = text.substring(0, start_loc) + diff_text2(aPatch.diffs) + + text.substring(start_loc + text1.length()); + } else { + // Imperfect match. Run a diff to get a framework of equivalent + // indices. + LinkedList diffs = diff_main(text1, text2, false); + if (text1.length() > this.Match_MaxBits + && diff_levenshtein(diffs) / (float) text1.length() + > this.Patch_DeleteThreshold) { + // The end points match, but the content is unacceptably bad. + results[x] = false; + } else { + diff_cleanupSemanticLossless(diffs); + int index1 = 0; + for (Diff aDiff : aPatch.diffs) { + if (aDiff.operation != Operation.EQUAL) { + int index2 = diff_xIndex(diffs, index1); + if (aDiff.operation == Operation.INSERT) { + // Insertion + text = text.substring(0, start_loc + index2) + aDiff.text + + text.substring(start_loc + index2); + } else if (aDiff.operation == Operation.DELETE) { + // Deletion + text = text.substring(0, start_loc + index2) + + text.substring(start_loc + diff_xIndex(diffs, + index1 + aDiff.text.length())); + } + } + if (aDiff.operation != Operation.DELETE) { + index1 += aDiff.text.length(); + } + } + } + } + } + x++; + } + // Strip the padding off. + text = text.substring(nullPadding.length(), text.length() + - nullPadding.length()); + return new Object[]{text, results}; + } + + /** + * Add some padding on text start and end so that edges can match something. + * Intended to be called only from within patch_apply. + * + * @param patches Array of Patch objects. + * @return The padding string added to each side. + */ + public String patch_addPadding(LinkedList patches) { + short paddingLength = this.Patch_Margin; + String nullPadding = ""; + for (short x = 1; x <= paddingLength; x++) { + nullPadding += String.valueOf((char) x); + } + + // Bump all the patches forward. + for (Patch aPatch : patches) { + aPatch.start1 += paddingLength; + aPatch.start2 += paddingLength; + } + + // Add some padding on start of first diff. + Patch patch = patches.getFirst(); + LinkedList diffs = patch.diffs; + if (diffs.isEmpty() || diffs.getFirst().operation != Operation.EQUAL) { + // Add nullPadding equality. + diffs.addFirst(new Diff(Operation.EQUAL, nullPadding)); + patch.start1 -= paddingLength; // Should be 0. + patch.start2 -= paddingLength; // Should be 0. + patch.length1 += paddingLength; + patch.length2 += paddingLength; + } else if (paddingLength > diffs.getFirst().text.length()) { + // Grow first equality. + Diff firstDiff = diffs.getFirst(); + int extraLength = paddingLength - firstDiff.text.length(); + firstDiff.text = nullPadding.substring(firstDiff.text.length()) + + firstDiff.text; + patch.start1 -= extraLength; + patch.start2 -= extraLength; + patch.length1 += extraLength; + patch.length2 += extraLength; + } + + // Add some padding on end of last diff. + patch = patches.getLast(); + diffs = patch.diffs; + if (diffs.isEmpty() || diffs.getLast().operation != Operation.EQUAL) { + // Add nullPadding equality. + diffs.addLast(new Diff(Operation.EQUAL, nullPadding)); + patch.length1 += paddingLength; + patch.length2 += paddingLength; + } else if (paddingLength > diffs.getLast().text.length()) { + // Grow last equality. + Diff lastDiff = diffs.getLast(); + int extraLength = paddingLength - lastDiff.text.length(); + lastDiff.text += nullPadding.substring(0, extraLength); + patch.length1 += extraLength; + patch.length2 += extraLength; + } + + return nullPadding; + } + + /** + * Look through the patches and break up any which are longer than the + * maximum limit of the match algorithm. + * Intended to be called only from within patch_apply. + * + * @param patches LinkedList of Patch objects. + */ + public void patch_splitMax(LinkedList patches) { + short patch_size = Match_MaxBits; + String precontext, postcontext; + Patch patch; + int start1, start2; + boolean empty; + Operation diff_type; + String diff_text; + ListIterator pointer = patches.listIterator(); + Patch bigpatch = pointer.hasNext() ? pointer.next() : null; + while (bigpatch != null) { + if (bigpatch.length1 <= Match_MaxBits) { + bigpatch = pointer.hasNext() ? pointer.next() : null; + continue; + } + // Remove the big old patch. + pointer.remove(); + start1 = bigpatch.start1; + start2 = bigpatch.start2; + precontext = ""; + while (!bigpatch.diffs.isEmpty()) { + // Create one of several smaller patches. + patch = new Patch(); + empty = true; + patch.start1 = start1 - precontext.length(); + patch.start2 = start2 - precontext.length(); + if (precontext.length() != 0) { + patch.length1 = patch.length2 = precontext.length(); + patch.diffs.add(new Diff(Operation.EQUAL, precontext)); + } + while (!bigpatch.diffs.isEmpty() + && patch.length1 < patch_size - Patch_Margin) { + diff_type = bigpatch.diffs.getFirst().operation; + diff_text = bigpatch.diffs.getFirst().text; + if (diff_type == Operation.INSERT) { + // Insertions are harmless. + patch.length2 += diff_text.length(); + start2 += diff_text.length(); + patch.diffs.addLast(bigpatch.diffs.removeFirst()); + empty = false; + } else if (diff_type == Operation.DELETE && patch.diffs.size() == 1 + && patch.diffs.getFirst().operation == Operation.EQUAL + && diff_text.length() > 2 * patch_size) { + // This is a large deletion. Let it pass in one chunk. + patch.length1 += diff_text.length(); + start1 += diff_text.length(); + empty = false; + patch.diffs.add(new Diff(diff_type, diff_text)); + bigpatch.diffs.removeFirst(); + } else { + // Deletion or equality. Only take as much as we can stomach. + diff_text = diff_text.substring(0, Math.min(diff_text.length(), + patch_size - patch.length1 - Patch_Margin)); + patch.length1 += diff_text.length(); + start1 += diff_text.length(); + if (diff_type == Operation.EQUAL) { + patch.length2 += diff_text.length(); + start2 += diff_text.length(); + } else { + empty = false; + } + patch.diffs.add(new Diff(diff_type, diff_text)); + if (diff_text.equals(bigpatch.diffs.getFirst().text)) { + bigpatch.diffs.removeFirst(); + } else { + bigpatch.diffs.getFirst().text = bigpatch.diffs.getFirst().text + .substring(diff_text.length()); + } + } + } + // Compute the head context for the next patch. + precontext = diff_text2(patch.diffs); + precontext = precontext.substring(Math.max(0, precontext.length() + - Patch_Margin)); + // Append the end context for this patch. + if (diff_text1(bigpatch.diffs).length() > Patch_Margin) { + postcontext = diff_text1(bigpatch.diffs).substring(0, Patch_Margin); + } else { + postcontext = diff_text1(bigpatch.diffs); + } + if (postcontext.length() != 0) { + patch.length1 += postcontext.length(); + patch.length2 += postcontext.length(); + if (!patch.diffs.isEmpty() + && patch.diffs.getLast().operation == Operation.EQUAL) { + patch.diffs.getLast().text += postcontext; + } else { + patch.diffs.add(new Diff(Operation.EQUAL, postcontext)); + } + } + if (!empty) { + pointer.add(patch); + } + } + bigpatch = pointer.hasNext() ? pointer.next() : null; + } + } + + /** + * Take a list of patches and return a textual representation. + * + * @param patches List of Patch objects. + * @return Text representation of patches. + */ + public String patch_toText(List patches) { + StringBuilder text = new StringBuilder(); + for (Patch aPatch : patches) { + text.append(aPatch); + } + return text.toString(); + } + + /** + * Parse a textual representation of patches and return a List of Patch + * objects. + * + * @param textline Text representation of patches. + * @return List of Patch objects. + * @throws IllegalArgumentException If invalid input. + */ + public List patch_fromText(String textline) + throws IllegalArgumentException { + List patches = new LinkedList(); + if (textline.length() == 0) { + return patches; + } + List textList = Arrays.asList(textline.split("\n")); + LinkedList text = new LinkedList(textList); + Patch patch; + Pattern patchHeader + = Pattern.compile("^@@ -(\\d+),?(\\d*) \\+(\\d+),?(\\d*) @@$"); + Matcher m; + char sign; + String line; + while (!text.isEmpty()) { + m = patchHeader.matcher(text.getFirst()); + if (!m.matches()) { + throw new IllegalArgumentException( + "Invalid patch string: " + text.getFirst()); + } + patch = new Patch(); + patches.add(patch); + patch.start1 = Integer.parseInt(m.group(1)); + if (m.group(2).length() == 0) { + patch.start1--; + patch.length1 = 1; + } else if (m.group(2).equals("0")) { + patch.length1 = 0; + } else { + patch.start1--; + patch.length1 = Integer.parseInt(m.group(2)); + } + + patch.start2 = Integer.parseInt(m.group(3)); + if (m.group(4).length() == 0) { + patch.start2--; + patch.length2 = 1; + } else if (m.group(4).equals("0")) { + patch.length2 = 0; + } else { + patch.start2--; + patch.length2 = Integer.parseInt(m.group(4)); + } + text.removeFirst(); + + while (!text.isEmpty()) { + try { + sign = text.getFirst().charAt(0); + } catch (IndexOutOfBoundsException e) { + // Blank line? Whatever. + text.removeFirst(); + continue; + } + line = text.getFirst().substring(1); + line = line.replace("+", "%2B"); // decode would change all "+" to " " + try { + line = URLDecoder.decode(line, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // Not likely on modern system. + throw new Error("This system does not support UTF-8.", e); + } catch (IllegalArgumentException e) { + // Malformed URI sequence. + throw new IllegalArgumentException( + "Illegal escape in patch_fromText: " + line, e); + } + if (sign == '-') { + // Deletion. + patch.diffs.add(new Diff(Operation.DELETE, line)); + } else if (sign == '+') { + // Insertion. + patch.diffs.add(new Diff(Operation.INSERT, line)); + } else if (sign == ' ') { + // Minor equality. + patch.diffs.add(new Diff(Operation.EQUAL, line)); + } else if (sign == '@') { + // Start of next patch. + break; + } else { + // WTF? + throw new IllegalArgumentException( + "Invalid patch mode '" + sign + "' in: " + line); + } + text.removeFirst(); + } + } + return patches; + } + + /** + * The data structure representing a diff is a Linked list of Diff objects: + * {Diff(Operation.DELETE, "Hello"), Diff(Operation.INSERT, "Goodbye"), + * Diff(Operation.EQUAL, " world.")} + * which means: delete "Hello", add "Goodbye" and keep " world." + */ + public enum Operation { + DELETE, INSERT, EQUAL + } + + /** + * Internal class for returning results from diff_linesToChars(). + * Other less paranoid languages just use a three-element array. + */ + protected static class LinesToCharsResult { + protected String chars1; + protected String chars2; + protected List lineArray; + + protected LinesToCharsResult(String chars1, String chars2, + List lineArray) { + this.chars1 = chars1; + this.chars2 = chars2; + this.lineArray = lineArray; + } + } + + /** + * Class representing one diff operation. + */ + public static class Diff { + /** + * One of: INSERT, DELETE or EQUAL. + */ + public Operation operation; + /** + * The text associated with this diff operation. + */ + public String text; + + /** + * Constructor. Initializes the diff with the provided values. + * + * @param operation One of INSERT, DELETE or EQUAL. + * @param text The text being applied. + */ + public Diff(Operation operation, String text) { + // Construct a diff with the specified operation and text. + this.operation = operation; + this.text = text; + } + + /** + * Display a human-readable version of this Diff. + * + * @return text version. + */ + public String toString() { + String prettyText = this.text.replace('\n', '\u00b6'); + return "Diff(" + this.operation + ",\"" + prettyText + "\")"; + } + + /** + * Create a numeric hash value for a Diff. + * This function is not used by DMP. + * + * @return Hash value. + */ + @Override + public int hashCode() { + final int prime = 31; + int result = (operation == null) ? 0 : operation.hashCode(); + result += prime * ((text == null) ? 0 : text.hashCode()); + return result; + } + + /** + * Is this Diff equivalent to another Diff? + * + * @param obj Another Diff to compare against. + * @return true or false. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Diff other = (Diff) obj; + if (operation != other.operation) { + return false; + } + if (text == null) { + if (other.text != null) { + return false; + } + } else if (!text.equals(other.text)) { + return false; + } + return true; + } + } + + /** + * Class representing one patch operation. + */ + public static class Patch { + public LinkedList diffs; + public int start1; + public int start2; + public int length1; + public int length2; + + /** + * Constructor. Initializes with an empty list of diffs. + */ + public Patch() { + this.diffs = new LinkedList(); + } + + /** + * Emmulate GNU diff's format. + * Header: @@ -382,8 +481,9 @@ + * Indicies are printed as 1-based, not 0-based. + * + * @return The GNU diff string. + */ + public String toString() { + String coords1, coords2; + if (this.length1 == 0) { + coords1 = this.start1 + ",0"; + } else if (this.length1 == 1) { + coords1 = Integer.toString(this.start1 + 1); + } else { + coords1 = (this.start1 + 1) + "," + this.length1; + } + if (this.length2 == 0) { + coords2 = this.start2 + ",0"; + } else if (this.length2 == 1) { + coords2 = Integer.toString(this.start2 + 1); + } else { + coords2 = (this.start2 + 1) + "," + this.length2; + } + StringBuilder text = new StringBuilder(); + text.append("@@ -").append(coords1).append(" +").append(coords2) + .append(" @@\n"); + // Escape the body of the patch with %xx notation. + for (Diff aDiff : this.diffs) { + switch (aDiff.operation) { + case INSERT: + text.append('+'); + break; + case DELETE: + text.append('-'); + break; + case EQUAL: + text.append(' '); + break; + } + try { + text.append(URLEncoder.encode(aDiff.text, "UTF-8").replace('+', ' ')) + .append("\n"); + } catch (UnsupportedEncodingException e) { + // Not likely on modern system. + throw new Error("This system does not support UTF-8.", e); + } + } + return unescapeForEncodeUriCompatability(text.toString()); + } + } +} 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 index ba67f2db..f5b968c3 100644 --- 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 @@ -3,6 +3,8 @@ import org.buildmlearn.toolkit.videocollectiontemplate.data.VideoContract; /** + * @brief Constants used in video collection template's simulator relating databases. + * * Created by Anupam (opticod) on 13/5/16. */ public class Constants { @@ -13,7 +15,6 @@ public class Constants { 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; 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 index 100248f3..98bf78cb 100644 --- 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 @@ -18,6 +18,8 @@ import org.buildmlearn.toolkit.videocollectiontemplate.Constants; /** + * @brief Adapter for displaying VideoCollection Template Editor data in simulator. + *

* Created by Anupam (opticod) on 12/5/16. */ public class VideoArrayAdapter extends CursorAdapter { 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 index dc3680fc..32f3d398 100644 --- 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 @@ -12,6 +12,8 @@ import javax.xml.parsers.ParserConfigurationException; /** + * @brief Contains xml data utils for video collection template's simulator. + * * Created by Anupam (opticod) on 13/5/16. */ public class DataUtils { 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 index 13416b0a..86fe969b 100644 --- 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 @@ -22,8 +22,11 @@ import javax.xml.parsers.ParserConfigurationException; /** + * @brief Used to parse XML and save in database for video collection template's simulator. + * * Created by Anupam (opticod) on 13/5/16. */ + public class FetchXMLTask extends AsyncTask { private final Context mContext; 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 index fb578880..9798517e 100644 --- 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 @@ -3,6 +3,8 @@ import android.provider.BaseColumns; /** + * @brief Contains database contracts for video collection template's simulator. + * * Created by Anupam (opticod) on 13/5/16. */ 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 index 2f4e8be9..7d7cad2b 100644 --- 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 @@ -7,6 +7,8 @@ import org.buildmlearn.toolkit.videocollectiontemplate.data.VideoContract.Videos; /** + * @brief DatabaseHelper for video collection template's simulator. + * * Created by Anupam (opticod) on 13/5/16. */ 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 index 513eeafc..db030366 100644 --- 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 @@ -9,6 +9,8 @@ import android.support.annotation.NonNull; /** + * @brief Contains database util functions for video collection template's simulator. + * * Created by Anupam (opticod) on 19/5/16. */ public class VideoDb { @@ -25,10 +27,6 @@ public void open() throws SQLException { db = dbHelper.getWritableDatabase(); } - public boolean isOpen() { - return db.isOpen(); - } - public void close() { dbHelper.close(); } 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 index 538bebb5..3e1f0a55 100644 --- 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 @@ -3,19 +3,13 @@ import android.os.Parcel; import android.os.Parcelable; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /** + * @brief Model used to save video entries in database for video collection template's simulator. + * * 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() { + public final static Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public VideoModel createFromParcel(Parcel parcel) { return new VideoModel(parcel); @@ -26,6 +20,12 @@ public VideoModel[] newArray(int size) { return new VideoModel[size]; } }; + + 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"; private String title; private String description; private String link; @@ -34,13 +34,6 @@ public VideoModel[] newArray(int size) { 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(); @@ -61,23 +54,6 @@ public void writeToParcel(Parcel dest, int flags) { 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; } 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 index a41debd2..12735783 100644 --- 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 @@ -26,6 +26,8 @@ import org.buildmlearn.toolkit.videocollectiontemplate.data.VideoDb; /** + * @brief Fragment containing details of video items in video collection template's simulator. + * * Created by Anupam (opticod) on 13/5/16. */ public class DetailActivityFragment extends Fragment implements LoaderCallbacks { @@ -82,6 +84,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { welcomeAlert.show(); assert welcomeAlert.findViewById(android.R.id.message) != null; assert welcomeAlert.findViewById(android.R.id.message) != null; + assert ((TextView) welcomeAlert.findViewById(android.R.id.message)) != null; ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); break; default: //do nothing diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/LastFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/LastFragment.java index 89459d99..f4ff4664 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/LastFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/LastFragment.java @@ -12,6 +12,8 @@ import org.buildmlearn.toolkit.R; /** + * @brief Fragment for displaying score to user in video collection template's simulator. + * * Created by Anupam (opticod) on 21/5/16. */ public class LastFragment extends Fragment { diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/MainActivityFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/MainActivityFragment.java index 4f71b250..1d0a7a35 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/MainActivityFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/MainActivityFragment.java @@ -29,6 +29,8 @@ import java.util.ArrayList; /** + * @brief Fragment containing list of videos in video collection template's simulator. + * * Created by Anupam (opticod) on 20/5/16. */ public class MainActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks { @@ -97,6 +99,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { welcomeAlert.show(); assert welcomeAlert.findViewById(android.R.id.message) != null; assert welcomeAlert.findViewById(android.R.id.message) != null; + assert ((TextView) welcomeAlert.findViewById(android.R.id.message)) != null; ((TextView) welcomeAlert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); break; default: //do nothing diff --git a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/SplashFragment.java b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/SplashFragment.java index c28dc316..defcb46f 100644 --- a/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/SplashFragment.java +++ b/source-code/app/src/main/java/org/buildmlearn/toolkit/videocollectiontemplate/fragment/SplashFragment.java @@ -17,6 +17,8 @@ import org.buildmlearn.toolkit.views.TextViewPlus; /** + * @brief Splash intro Fragment for video collection template's simulator. + * * Created by Anupam (opticod) on 21/5/16. */ public class SplashFragment extends Fragment { diff --git a/source-code/app/src/main/res/anim/from_middle.xml b/source-code/app/src/main/res/anim/from_middle.xml deleted file mode 100644 index 56ee58f5..00000000 --- a/source-code/app/src/main/res/anim/from_middle.xml +++ /dev/null @@ -1,8 +0,0 @@ - - \ No newline at end of file diff --git a/source-code/app/src/main/res/anim/to_middle.xml b/source-code/app/src/main/res/anim/to_middle.xml deleted file mode 100644 index c3088122..00000000 --- a/source-code/app/src/main/res/anim/to_middle.xml +++ /dev/null @@ -1,8 +0,0 @@ - - \ No newline at end of file diff --git a/source-code/app/src/main/res/drawable-hdpi/ic_action_device_access_volume_on.png b/source-code/app/src/main/res/drawable-hdpi/ic_action_device_access_volume_on.png deleted file mode 100755 index d402cd26..00000000 Binary files a/source-code/app/src/main/res/drawable-hdpi/ic_action_device_access_volume_on.png and /dev/null differ diff --git a/source-code/app/src/main/res/drawable-hdpi/ic_group_work_black_24dp.png b/source-code/app/src/main/res/drawable-hdpi/ic_group_work_black_24dp.png new file mode 100755 index 00000000..994667bd Binary files /dev/null and b/source-code/app/src/main/res/drawable-hdpi/ic_group_work_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-hdpi/ic_keyboard_capslock_black_24dp.png b/source-code/app/src/main/res/drawable-hdpi/ic_keyboard_capslock_black_24dp.png new file mode 100644 index 00000000..7f0d75c1 Binary files /dev/null and b/source-code/app/src/main/res/drawable-hdpi/ic_keyboard_capslock_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-hdpi/ic_keyboard_capslock_black_down_24dp.png b/source-code/app/src/main/res/drawable-hdpi/ic_keyboard_capslock_black_down_24dp.png new file mode 100644 index 00000000..2ff816d0 Binary files /dev/null and b/source-code/app/src/main/res/drawable-hdpi/ic_keyboard_capslock_black_down_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-hdpi/ic_record_voice_over_black_36dp.png b/source-code/app/src/main/res/drawable-hdpi/ic_record_voice_over_black_36dp.png new file mode 100755 index 00000000..b65995d9 Binary files /dev/null and b/source-code/app/src/main/res/drawable-hdpi/ic_record_voice_over_black_36dp.png differ diff --git a/source-code/app/src/main/res/drawable-hdpi/ic_record_voice_over_black_48dp.png b/source-code/app/src/main/res/drawable-hdpi/ic_record_voice_over_black_48dp.png new file mode 100644 index 00000000..d1a55ad8 Binary files /dev/null and b/source-code/app/src/main/res/drawable-hdpi/ic_record_voice_over_black_48dp.png differ diff --git a/source-code/app/src/main/res/drawable-mdpi/ic_action_device_access_volume_on.png b/source-code/app/src/main/res/drawable-mdpi/ic_action_device_access_volume_on.png deleted file mode 100755 index 9a790aa7..00000000 Binary files a/source-code/app/src/main/res/drawable-mdpi/ic_action_device_access_volume_on.png and /dev/null differ diff --git a/source-code/app/src/main/res/drawable-mdpi/ic_group_work_black_24dp.png b/source-code/app/src/main/res/drawable-mdpi/ic_group_work_black_24dp.png new file mode 100755 index 00000000..7f523caf Binary files /dev/null and b/source-code/app/src/main/res/drawable-mdpi/ic_group_work_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-mdpi/ic_keyboard_capslock_black_24dp.png b/source-code/app/src/main/res/drawable-mdpi/ic_keyboard_capslock_black_24dp.png new file mode 100644 index 00000000..aa6d98ec Binary files /dev/null and b/source-code/app/src/main/res/drawable-mdpi/ic_keyboard_capslock_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-mdpi/ic_keyboard_capslock_black_down_24dp.png b/source-code/app/src/main/res/drawable-mdpi/ic_keyboard_capslock_black_down_24dp.png new file mode 100644 index 00000000..9c4e8ada Binary files /dev/null and b/source-code/app/src/main/res/drawable-mdpi/ic_keyboard_capslock_black_down_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-mdpi/ic_record_voice_over_black_36dp.png b/source-code/app/src/main/res/drawable-mdpi/ic_record_voice_over_black_36dp.png new file mode 100755 index 00000000..04cbe6a0 Binary files /dev/null and b/source-code/app/src/main/res/drawable-mdpi/ic_record_voice_over_black_36dp.png differ diff --git a/source-code/app/src/main/res/drawable-mdpi/ic_record_voice_over_black_48dp.png b/source-code/app/src/main/res/drawable-mdpi/ic_record_voice_over_black_48dp.png new file mode 100644 index 00000000..2bc36fec Binary files /dev/null and b/source-code/app/src/main/res/drawable-mdpi/ic_record_voice_over_black_48dp.png differ diff --git a/source-code/app/src/main/res/drawable-xhdpi/ic_action_device_access_volume_on.png b/source-code/app/src/main/res/drawable-xhdpi/ic_action_device_access_volume_on.png deleted file mode 100755 index 6ed9005e..00000000 Binary files a/source-code/app/src/main/res/drawable-xhdpi/ic_action_device_access_volume_on.png and /dev/null differ diff --git a/source-code/app/src/main/res/drawable-xhdpi/ic_group_work_black_24dp.png b/source-code/app/src/main/res/drawable-xhdpi/ic_group_work_black_24dp.png new file mode 100755 index 00000000..68553c64 Binary files /dev/null and b/source-code/app/src/main/res/drawable-xhdpi/ic_group_work_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xhdpi/ic_keyboard_capslock_black_24dp.png b/source-code/app/src/main/res/drawable-xhdpi/ic_keyboard_capslock_black_24dp.png new file mode 100644 index 00000000..3e23246a Binary files /dev/null and b/source-code/app/src/main/res/drawable-xhdpi/ic_keyboard_capslock_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xhdpi/ic_keyboard_capslock_black_down_24dp.png b/source-code/app/src/main/res/drawable-xhdpi/ic_keyboard_capslock_black_down_24dp.png new file mode 100644 index 00000000..0f81bfc0 Binary files /dev/null and b/source-code/app/src/main/res/drawable-xhdpi/ic_keyboard_capslock_black_down_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xhdpi/ic_record_voice_over_black_36dp.png b/source-code/app/src/main/res/drawable-xhdpi/ic_record_voice_over_black_36dp.png new file mode 100755 index 00000000..f598c878 Binary files /dev/null and b/source-code/app/src/main/res/drawable-xhdpi/ic_record_voice_over_black_36dp.png differ diff --git a/source-code/app/src/main/res/drawable-xhdpi/ic_record_voice_over_black_48dp.png b/source-code/app/src/main/res/drawable-xhdpi/ic_record_voice_over_black_48dp.png new file mode 100644 index 00000000..6c9134bb Binary files /dev/null and b/source-code/app/src/main/res/drawable-xhdpi/ic_record_voice_over_black_48dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxhdpi/ic_action_device_access_volume_on.png b/source-code/app/src/main/res/drawable-xxhdpi/ic_action_device_access_volume_on.png deleted file mode 100755 index a86a8431..00000000 Binary files a/source-code/app/src/main/res/drawable-xxhdpi/ic_action_device_access_volume_on.png and /dev/null differ diff --git a/source-code/app/src/main/res/drawable-xxhdpi/ic_group_work_black_24dp.png b/source-code/app/src/main/res/drawable-xxhdpi/ic_group_work_black_24dp.png new file mode 100755 index 00000000..25642318 Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxhdpi/ic_group_work_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxhdpi/ic_keyboard_capslock_black_24dp.png b/source-code/app/src/main/res/drawable-xxhdpi/ic_keyboard_capslock_black_24dp.png new file mode 100644 index 00000000..72ad88ce Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxhdpi/ic_keyboard_capslock_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxhdpi/ic_keyboard_capslock_black_down_24dp.png b/source-code/app/src/main/res/drawable-xxhdpi/ic_keyboard_capslock_black_down_24dp.png new file mode 100644 index 00000000..15bc2389 Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxhdpi/ic_keyboard_capslock_black_down_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxhdpi/ic_record_voice_over_black_36dp.png b/source-code/app/src/main/res/drawable-xxhdpi/ic_record_voice_over_black_36dp.png new file mode 100755 index 00000000..b0abe0ad Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxhdpi/ic_record_voice_over_black_36dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxhdpi/ic_record_voice_over_black_48dp.png b/source-code/app/src/main/res/drawable-xxhdpi/ic_record_voice_over_black_48dp.png new file mode 100644 index 00000000..f9d2da11 Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxhdpi/ic_record_voice_over_black_48dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxxhdpi/ic_action_device_access_volume_on.png b/source-code/app/src/main/res/drawable-xxxhdpi/ic_action_device_access_volume_on.png deleted file mode 100755 index 9834bb7e..00000000 Binary files a/source-code/app/src/main/res/drawable-xxxhdpi/ic_action_device_access_volume_on.png and /dev/null differ diff --git a/source-code/app/src/main/res/drawable-xxxhdpi/ic_group_work_black_24dp.png b/source-code/app/src/main/res/drawable-xxxhdpi/ic_group_work_black_24dp.png new file mode 100755 index 00000000..30e47e5e Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxxhdpi/ic_group_work_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxxhdpi/ic_keyboard_capslock_black_24dp.png b/source-code/app/src/main/res/drawable-xxxhdpi/ic_keyboard_capslock_black_24dp.png new file mode 100644 index 00000000..f85fcc7e Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxxhdpi/ic_keyboard_capslock_black_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxxhdpi/ic_keyboard_capslock_black_down_24dp.png b/source-code/app/src/main/res/drawable-xxxhdpi/ic_keyboard_capslock_black_down_24dp.png new file mode 100644 index 00000000..d9a21e0f Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxxhdpi/ic_keyboard_capslock_black_down_24dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxxhdpi/ic_record_voice_over_black_36dp.png b/source-code/app/src/main/res/drawable-xxxhdpi/ic_record_voice_over_black_36dp.png new file mode 100755 index 00000000..82c2d84a Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxxhdpi/ic_record_voice_over_black_36dp.png differ diff --git a/source-code/app/src/main/res/drawable-xxxhdpi/ic_record_voice_over_black_48dp.png b/source-code/app/src/main/res/drawable-xxxhdpi/ic_record_voice_over_black_48dp.png new file mode 100644 index 00000000..f505b5d2 Binary files /dev/null and b/source-code/app/src/main/res/drawable-xxxhdpi/ic_record_voice_over_black_48dp.png differ diff --git a/source-code/app/src/main/res/drawable/basic_m_learning.png b/source-code/app/src/main/res/drawable/basic_m_learning.png deleted file mode 100644 index 7e0e7c26..00000000 Binary files a/source-code/app/src/main/res/drawable/basic_m_learning.png and /dev/null differ diff --git a/source-code/app/src/main/res/drawable/dictation.png b/source-code/app/src/main/res/drawable/dictation.png new file mode 100755 index 00000000..d037e85c Binary files /dev/null and b/source-code/app/src/main/res/drawable/dictation.png differ diff --git a/source-code/app/src/main/res/drawable/flash.png b/source-code/app/src/main/res/drawable/flash.png new file mode 100755 index 00000000..779f7892 Binary files /dev/null and b/source-code/app/src/main/res/drawable/flash.png differ diff --git a/source-code/app/src/main/res/drawable/image_quiz.jpg b/source-code/app/src/main/res/drawable/image_quiz.jpg new file mode 100644 index 00000000..eed89f9a Binary files /dev/null and b/source-code/app/src/main/res/drawable/image_quiz.jpg differ diff --git a/source-code/app/src/main/res/drawable/info_template.png b/source-code/app/src/main/res/drawable/info_template.png index 2d24ab7f..2311ef18 100755 Binary files a/source-code/app/src/main/res/drawable/info_template.png and b/source-code/app/src/main/res/drawable/info_template.png differ diff --git a/source-code/app/src/main/res/drawable/match_template.png b/source-code/app/src/main/res/drawable/match_template.png new file mode 100755 index 00000000..4f2a8460 Binary files /dev/null and b/source-code/app/src/main/res/drawable/match_template.png differ diff --git a/source-code/app/src/main/res/drawable/quiz.png b/source-code/app/src/main/res/drawable/quiz.png new file mode 100755 index 00000000..4d63358f Binary files /dev/null and b/source-code/app/src/main/res/drawable/quiz.png differ diff --git a/source-code/app/src/main/res/drawable/side_nav_bar_flash.xml b/source-code/app/src/main/res/drawable/side_nav_bar_flash.xml new file mode 100644 index 00000000..137919ed --- /dev/null +++ b/source-code/app/src/main/res/drawable/side_nav_bar_flash.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/source-code/app/src/main/res/drawable/spell_side_nav_bar.xml b/source-code/app/src/main/res/drawable/spell_side_nav_bar.xml new file mode 100644 index 00000000..2f438205 --- /dev/null +++ b/source-code/app/src/main/res/drawable/spell_side_nav_bar.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/source-code/app/src/main/res/drawable/spelling.png b/source-code/app/src/main/res/drawable/spelling.png new file mode 100755 index 00000000..dcb6cc0f Binary files /dev/null and b/source-code/app/src/main/res/drawable/spelling.png differ diff --git a/source-code/app/src/main/res/layout-land/fragment_home.xml b/source-code/app/src/main/res/layout-land/fragment_home.xml index d814cbfe..58af0e9d 100644 --- a/source-code/app/src/main/res/layout-land/fragment_home.xml +++ b/source-code/app/src/main/res/layout-land/fragment_home.xml @@ -32,7 +32,9 @@ - - - - - - - - - - - - - - - - - - diff --git a/source-code/app/src/main/res/layout/activity_about_buildm_learn.xml b/source-code/app/src/main/res/layout/activity_about_buildm_learn.xml index 9ed701f0..fba5edc5 100644 --- a/source-code/app/src/main/res/layout/activity_about_buildm_learn.xml +++ b/source-code/app/src/main/res/layout/activity_about_buildm_learn.xml @@ -29,6 +29,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" + android:contentDescription="@string/buildmlearn_logo" android:padding="5dp" android:src="@drawable/logo_bg_dark" /> diff --git a/source-code/app/src/main/res/layout/activity_first_run.xml b/source-code/app/src/main/res/layout/activity_first_run.xml index 7ad3b5fb..d9416f2b 100644 --- a/source-code/app/src/main/res/layout/activity_first_run.xml +++ b/source-code/app/src/main/res/layout/activity_first_run.xml @@ -9,6 +9,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" + android:contentDescription="@string/buildmlearn_backdrop_image" android:scaleType="centerCrop" android:src="@drawable/first_run_bg" /> @@ -23,6 +24,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" + android:contentDescription="@string/buildmlearn_logo" android:scaleType="centerCrop" android:src="@drawable/logo_70" /> diff --git a/source-code/app/src/main/res/layout/activity_simulator.xml b/source-code/app/src/main/res/layout/activity_simulator.xml index c7317665..d71e745c 100644 --- a/source-code/app/src/main/res/layout/activity_simulator.xml +++ b/source-code/app/src/main/res/layout/activity_simulator.xml @@ -18,6 +18,7 @@ android:layout_height="match_parent" android:layout_above="@+id/imageView5" android:layout_below="@+id/imageView3" + android:layout_toEndOf="@+id/imageView2" android:layout_toLeftOf="@+id/imageView4" android:layout_toRightOf="@+id/imageView2" android:layout_toStartOf="@+id/imageView4" diff --git a/source-code/app/src/main/res/layout/activity_template_editor.xml b/source-code/app/src/main/res/layout/activity_template_editor.xml index 89403903..42d48d6b 100644 --- a/source-code/app/src/main/res/layout/activity_template_editor.xml +++ b/source-code/app/src/main/res/layout/activity_template_editor.xml @@ -49,8 +49,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" + android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_marginBottom="@dimen/floating_action_button_padding_bottom_right" + android:layout_marginEnd="@dimen/floating_action_button_padding_bottom_right" android:layout_marginRight="@dimen/floating_action_button_padding_bottom_right" android:src="@drawable/ic_add_white_24dp" fab:backgroundTint="@color/color_accent" diff --git a/source-code/app/src/main/res/layout/activity_template_grid.xml b/source-code/app/src/main/res/layout/activity_template_grid.xml deleted file mode 100644 index 63aed6b2..00000000 --- a/source-code/app/src/main/res/layout/activity_template_grid.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - diff --git a/source-code/app/src/main/res/layout/activity_template_list.xml b/source-code/app/src/main/res/layout/activity_template_list.xml index 39b7b944..215bf61f 100644 --- a/source-code/app/src/main/res/layout/activity_template_list.xml +++ b/source-code/app/src/main/res/layout/activity_template_list.xml @@ -6,7 +6,7 @@ - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source-code/app/src/main/res/layout/app_bar_main_flash.xml b/source-code/app/src/main/res/layout/app_bar_main_flash.xml new file mode 100644 index 00000000..f8c2a550 --- /dev/null +++ b/source-code/app/src/main/res/layout/app_bar_main_flash.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/source-code/app/src/main/res/layout/app_bar_main_spell.xml b/source-code/app/src/main/res/layout/app_bar_main_spell.xml new file mode 100644 index 00000000..f5599ce3 --- /dev/null +++ b/source-code/app/src/main/res/layout/app_bar_main_spell.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/source-code/app/src/main/res/layout/app_bar_response_spell.xml b/source-code/app/src/main/res/layout/app_bar_response_spell.xml new file mode 100644 index 00000000..0e6184b7 --- /dev/null +++ b/source-code/app/src/main/res/layout/app_bar_response_spell.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/source-code/app/src/main/res/layout/comprehension_content_main.xml b/source-code/app/src/main/res/layout/comprehension_content_main.xml index 628e7477..6c269a08 100644 --- a/source-code/app/src/main/res/layout/comprehension_content_main.xml +++ b/source-code/app/src/main/res/layout/comprehension_content_main.xml @@ -25,6 +25,7 @@ android:id="@+id/timer" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:paddingBottom="@dimen/activity_vertical_margin_simulator" android:paddingLeft="@dimen/activity_vertical_margin_simulator" @@ -61,6 +62,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" + android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_below="@+id/passage" android:background="@android:color/transparent" diff --git a/source-code/app/src/main/res/layout/comprehension_content_question.xml b/source-code/app/src/main/res/layout/comprehension_content_question.xml index 05d62dc8..6a6d89a2 100644 --- a/source-code/app/src/main/res/layout/comprehension_content_question.xml +++ b/source-code/app/src/main/res/layout/comprehension_content_question.xml @@ -4,9 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/activity_vertical_margin_simulator" android:layout_marginTop="49dp" - android:paddingTop="@dimen/activity_vertical_margin_simulator" tools:context=".comprehensiontemplate.fragment.QuestionFragment" tools:showIn="@layout/comprehension_app_bar_question"> @@ -16,7 +14,7 @@ card_view:cardBackgroundColor="#FFFFFF" card_view:cardCornerRadius="3.27dp" card_view:cardElevation="3.27dp" - card_view:cardUseCompatPadding="false"> + card_view:cardUseCompatPadding="true"> + android:layout_marginBottom="@dimen/comprehension_radio_button_margin_top"> @@ -106,6 +111,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" + android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:background="@android:color/transparent" android:paddingBottom="@dimen/headline_leading_simulator" diff --git a/source-code/app/src/main/res/layout/comprehension_fragment_last.xml b/source-code/app/src/main/res/layout/comprehension_fragment_last.xml index 07a661d8..9958bd7a 100644 --- a/source-code/app/src/main/res/layout/comprehension_fragment_last.xml +++ b/source-code/app/src/main/res/layout/comprehension_fragment_last.xml @@ -1,6 +1,7 @@ @@ -25,7 +26,10 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="@dimen/comprehension_cardHeightLastActivity" - android:layout_marginTop="@dimen/comprehension_paddingTop"> + card_view:cardBackgroundColor="#FFFFFF" + card_view:cardCornerRadius="3.27dp" + card_view:cardElevation="3.27dp" + card_view:cardUseCompatPadding="true"> diff --git a/source-code/app/src/main/res/layout/comprehension_meta_item.xml b/source-code/app/src/main/res/layout/comprehension_meta_item.xml index bd631190..a959f971 100644 --- a/source-code/app/src/main/res/layout/comprehension_meta_item.xml +++ b/source-code/app/src/main/res/layout/comprehension_meta_item.xml @@ -16,22 +16,22 @@ style="@style/TextView.Title.Bold" class="org.buildmlearn.toolkit.views.TextViewPlus" android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" android:layout_weight="1" android:lineSpacingMultiplier="1.2" android:paddingBottom="8dp" - android:paddingTop="16dp" - android:text="English Tutorial" /> + android:paddingTop="16dp" /> + android:paddingTop="16dp" /> @@ -40,9 +40,10 @@ style="@style/TextView.Body1" class="org.buildmlearn.toolkit.views.TextViewPlus" android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" android:lineSpacingMultiplier="1.2" android:paddingBottom="16dp" - android:paddingRight="16dp" - android:text="This is a long long passage of some cool meta details. Made only for BuildmLearn as a pat of GSoC Project." /> + android:paddingEnd="16dp" + android:paddingRight="16dp" /> \ No newline at end of file diff --git a/source-code/app/src/main/res/layout/content_main_flash.xml b/source-code/app/src/main/res/layout/content_main_flash.xml new file mode 100644 index 00000000..834bbbf5 --- /dev/null +++ b/source-code/app/src/main/res/layout/content_main_flash.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + - - \ No newline at end of file diff --git a/source-code/app/src/main/res/layout/flash_template_item.xml b/source-code/app/src/main/res/layout/flash_template_item.xml index d97aaf58..bebd4795 100644 --- a/source-code/app/src/main/res/layout/flash_template_item.xml +++ b/source-code/app/src/main/res/layout/flash_template_item.xml @@ -27,6 +27,7 @@ android:layout_width="match_parent" android:layout_height="150dp" android:adjustViewBounds="true" + android:contentDescription="@string/flashcard_image" android:scaleType="centerCrop" android:src="@drawable/bg_card"/> @@ -40,6 +41,7 @@ android:id="@+id/flash_item_edit" style="@style/TextView.CircleIcon" android:layout_gravity="center_vertical" + android:contentDescription="@string/info_edit_title" android:padding="2dp" android:src="@drawable/menu_edit_template_item"/> @@ -55,9 +57,9 @@ style="@style/TextView.Title.Thin" class="org.buildmlearn.toolkit.views.TextViewPlus" android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" android:paddingBottom="8dp" - android:paddingTop="16dp" - android:text="Somedifficultword"/> + android:paddingTop="16dp" /> + android:layout_marginStart="16dp" + android:paddingBottom="4dp" /> + android:layout_marginStart="16dp" + android:paddingBottom="8dp" /> @@ -84,8 +86,10 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center" + android:layout_marginEnd="16dp" android:layout_marginRight="16dp" android:adjustViewBounds="true" + android:contentDescription="@string/delete_item" android:scaleType="centerInside" android:src="@drawable/template_delete"/> diff --git a/source-code/app/src/main/res/layout/fragment_detail_dict.xml b/source-code/app/src/main/res/layout/fragment_detail_dict.xml new file mode 100644 index 00000000..66ca0f80 --- /dev/null +++ b/source-code/app/src/main/res/layout/fragment_detail_dict.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + - - \ No newline at end of file diff --git a/source-code/app/src/main/res/layout/spelling_fragment_spelling.xml b/source-code/app/src/main/res/layout/spelling_fragment_spelling.xml deleted file mode 100644 index 15f6c16d..00000000 --- a/source-code/app/src/main/res/layout/spelling_fragment_spelling.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - - - -