PageRenderTime 74ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/MeadowEast/xue/LearnActivity.java

https://bitbucket.org/jzallas/xue-chinese-study-cards
Java | 562 lines | 377 code | 67 blank | 118 comment | 41 complexity | d39537faf89416f6ccc6230e3c519399 MD5 | raw file
  1. package com.MeadowEast.xue;
  2. import java.io.IOException;
  3. import android.annotation.SuppressLint;
  4. import android.annotation.TargetApi;
  5. import android.app.Activity;
  6. import android.app.AlertDialog;
  7. import android.content.ClipData;
  8. import android.content.ClipboardManager;
  9. import android.content.DialogInterface;
  10. import android.content.Intent;
  11. import android.content.SharedPreferences;
  12. import android.graphics.Color;
  13. import android.media.MediaPlayer;
  14. import android.net.Uri;
  15. import android.os.Build;
  16. import android.os.Bundle;
  17. import android.os.SystemClock;
  18. import android.preference.PreferenceManager;
  19. import android.util.Log;
  20. import android.view.GestureDetector;
  21. import android.view.GestureDetector.SimpleOnGestureListener;
  22. import android.view.KeyEvent;
  23. import android.view.MotionEvent;
  24. import android.view.View;
  25. import android.view.View.OnClickListener;
  26. import android.view.View.OnLongClickListener;
  27. import android.view.animation.TranslateAnimation;
  28. import android.widget.Button;
  29. import android.widget.Chronometer;
  30. import android.widget.LinearLayout;
  31. import android.widget.TextView;
  32. import android.widget.Toast;
  33. @SuppressLint("NewApi")
  34. public class LearnActivity extends Activity implements OnClickListener,
  35. OnLongClickListener, ClipboardManager.OnPrimaryClipChangedListener {
  36. static final String TAG = "LearnActivity";
  37. static int ECDeckSize, CEDeckSize, ECTarget, CETarget,
  38. minutesBetweenDuplicate;
  39. //timer
  40. private Chronometer chronometer;
  41. long timeWhenStopped = 0;
  42. // Swipe Gesture Detector
  43. private static final int SWIPE_MIN_DISTANCE = 8; // 90; // 120;
  44. private static final int SWIPE_MAX_OFF_PATH = 150; // 280 // 200;
  45. private static final int SWIPE_THRESHOLD_VELOCITY = 200;
  46. private GestureDetector gestureDetector; // imported GestureDetector
  47. View.OnTouchListener gestureListener;
  48. //sound items
  49. private MediaPlayer mPlayer;
  50. private boolean soundFx; // , enableUpdates;
  51. LearningProject lp;
  52. // clipboard monitor
  53. ClipboardManager clipBoard;
  54. int itemsShown;
  55. TextView prompt, answer, other, status;
  56. Button advance, okay;
  57. @Override
  58. protected void onPause() {
  59. // TODO Auto-generated method stub
  60. super.onPause();
  61. // un-register on pause to prevent android 4.3 bug
  62. clipBoard.removePrimaryClipChangedListener(this);
  63. timeWhenStopped = chronometer.getBase() - SystemClock.elapsedRealtime();
  64. chronometer.stop();
  65. }
  66. @Override
  67. protected void onResume() {
  68. // TODO Auto-generated method stub
  69. super.onResume();
  70. // clear clipdata
  71. ClipData data = ClipData.newPlainText("", "");
  72. clipBoard.setPrimaryClip(data);
  73. // re-register on resume to prevent android 4.3 bug
  74. clipBoard.addPrimaryClipChangedListener(this);
  75. chronometer.setBase(SystemClock.elapsedRealtime() + timeWhenStopped);
  76. chronometer.start();
  77. }
  78. @Override
  79. public void onCreate(Bundle savedInstanceState) {
  80. super.onCreate(savedInstanceState);
  81. setContentView(R.layout.activity_learn);
  82. setupActionBar();
  83. loadSettings();
  84. Log.d(TAG, "Entering onCreate");
  85. clipBoard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
  86. chronometer = (Chronometer) findViewById(R.id.chronometer1);
  87. chronometer.start();
  88. gestureDetector = new GestureDetector(this, new MyGestureDetector());
  89. gestureListener = new View.OnTouchListener() {
  90. public boolean onTouch(View v, MotionEvent event) {
  91. return gestureDetector.onTouchEvent(event);
  92. }
  93. };
  94. itemsShown = 0;
  95. prompt = (TextView) findViewById(R.id.promptTextView);
  96. status = (TextView) findViewById(R.id.statusTextView);
  97. other = (TextView) findViewById(R.id.otherTextView);
  98. answer = (TextView) findViewById(R.id.answerTextView);
  99. advance = (Button) findViewById(R.id.advanceButton);
  100. okay = (Button) findViewById(R.id.okayButton);
  101. // add listeners
  102. prompt.setOnClickListener(LearnActivity.this);
  103. prompt.setOnTouchListener(gestureListener);
  104. status.setOnClickListener(LearnActivity.this);
  105. status.setOnTouchListener(gestureListener);
  106. other.setOnClickListener(LearnActivity.this);
  107. other.setOnTouchListener(gestureListener);
  108. answer.setOnClickListener(LearnActivity.this);
  109. answer.setOnTouchListener(gestureListener);
  110. // findViewById(R.id.advanceButton).setOnClickListener(this);
  111. // findViewById(R.id.okayButton).setOnClickListener(this);
  112. findViewById(R.id.promptTextView).setOnLongClickListener(this);
  113. findViewById(R.id.answerTextView).setOnLongClickListener(this);
  114. findViewById(R.id.otherTextView).setOnLongClickListener(this);
  115. if (MainActivity.mode.equals("ec")) {
  116. lp = new EnglishChineseProject(ECDeckSize, ECTarget,
  117. minutesBetweenDuplicate);
  118. other.setTextIsSelectable(true);
  119. } else {
  120. lp = new ChineseEnglishProject(CEDeckSize, CETarget,
  121. minutesBetweenDuplicate);
  122. prompt.setTextIsSelectable(true);
  123. }
  124. clearContent();
  125. doAdvance();
  126. }
  127. public void onPrimaryClipChanged() {
  128. // do something useful here with the clipboard
  129. // get clipdata and make url
  130. String url = "http://www.mdbg.net/chindict/chindict.php?page=worddict&wdrst=0&wdqb="
  131. + clipBoard.getText().toString();
  132. // launch some browser with an implicit intent
  133. Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
  134. try {
  135. startActivity(browserIntent);
  136. } catch (android.content.ActivityNotFoundException ex) {
  137. Toast.makeText(this, "No browser found",
  138. Toast.LENGTH_SHORT).show();
  139. }
  140. }
  141. /**
  142. * Set up the {@link android.app.ActionBar}, if the API is available.
  143. */
  144. @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  145. private void setupActionBar() {
  146. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
  147. getActionBar().setDisplayHomeAsUpEnabled(false);
  148. }
  149. }
  150. private void loadSettings() {
  151. // SET BACKGROUND COLOR
  152. SharedPreferences sharedPref = PreferenceManager
  153. .getDefaultSharedPreferences(this);
  154. LinearLayout learnLayout = (LinearLayout) findViewById(R.id.LearnLayout);
  155. learnLayout.setBackgroundColor(Color.parseColor(sharedPref
  156. .getString("bg_color",
  157. getResources().getString(R.color.background_color5))));
  158. // ENABLE OR DISABLE SOUND
  159. soundFx = sharedPref.getBoolean("sound_checkbox", true);
  160. //EDIT DECK SIZES PER SETTINGS
  161. ECDeckSize = Integer.parseInt(sharedPref.getString("ec_deck_size_list", "40"));
  162. CEDeckSize = Integer.parseInt(sharedPref.getString("ce_deck_size_list", "60"));
  163. //EDIT TARGET PER SETTINGS
  164. ECTarget = Integer.parseInt(sharedPref.getString("ec_target_list", "700"));
  165. CETarget = Integer.parseInt(sharedPref.getString("ce_target_list", "700"));
  166. //GET DUPLICATE FREQUENCY
  167. minutesBetweenDuplicate = Integer.parseInt(sharedPref.getString("duplicate_freq_list", "1440"));
  168. }
  169. private void doAdvance() {
  170. Log.d("!", "doAdvance CALLED!");
  171. if (itemsShown == 0) {
  172. if (lp.next()) {
  173. prompt.setText(lp.prompt());
  174. status.setText(lp.deckStatus());
  175. itemsShown++;
  176. } else {
  177. Log.d(TAG, "Error: Deck starts empty");
  178. throw new IllegalStateException("Error: Deck starts empty.");
  179. }
  180. } else if (itemsShown == 1) {
  181. answer.setText(lp.answer());
  182. itemsShown++;
  183. animateBottomAnswer();
  184. // playSound();
  185. } else if (itemsShown == 2) {
  186. other.setText(lp.other());
  187. // advance.setText("next");
  188. itemsShown++;
  189. animateBottomOther();
  190. // playSound();
  191. } else if (itemsShown == 3) {
  192. // Got it wrong
  193. // advance.setText("show");
  194. // lp.wrong();
  195. // lp.next();
  196. // clearContent();
  197. // prompt.setText(lp.prompt());
  198. // itemsShown = 1;
  199. // status.setText(lp.deckStatus());
  200. }
  201. }
  202. private void clearContent() {
  203. prompt.setText("");
  204. answer.setText("");
  205. other.setText("");
  206. }
  207. // swiping up - removing card from deck
  208. private void doOkay(){
  209. if (okay.getText().equals("done")) //if done
  210. try {
  211. Log.d(TAG,"DONE");
  212. // prompt user to click "done" to end activity and write results...
  213. Toast.makeText(this, "Your progress has been saved",
  214. Toast.LENGTH_LONG).show();
  215. lp.log(lp.queueStatus()); //write to log
  216. lp.writeStatus(); //save indexSets and timestamps
  217. finish(); //end activity
  218. return;
  219. //System.exit(0);
  220. } catch (IOException e) {
  221. Log.d(TAG, "couldn't write Status");
  222. return;
  223. }
  224. // Do nothing unless answer has been seen
  225. if (itemsShown < 2) return;
  226. // Got it right
  227. lp.right();
  228. if (lp.next()){
  229. advance.setText("show");
  230. clearContent();
  231. prompt.setText(lp.prompt());
  232. itemsShown = 1;
  233. status.setText(lp.deckStatus());
  234. animateTop();
  235. playCorrectSound();
  236. } else {
  237. advance.setText("show");
  238. clearContent();
  239. status.setText("Swipe up to save the progress to disk.\nSwipe right to undo.");
  240. prompt.setText("Congratulations!\nYou have reached end of deck.");
  241. answer.setText("");
  242. okay.setText("done");
  243. // okay.setVisibility(View.GONE);
  244. itemsShown = 2;
  245. playCorrectSound();
  246. }
  247. // else {
  248. // Log.d("!","INSIDE ELSE");
  249. // ((ViewManager) advance.getParent()).removeView(advance);
  250. // status.setText("");
  251. // okay.setText("done");
  252. // clearContent();
  253. // animateTop();
  254. // playCorrectSound();
  255. // }
  256. }
  257. /*******************************************************************
  258. * TranslateAnimation transAnimation= new TranslateAnimation(fromXposition,
  259. * toXPosition, fromYPosition, toYPosition);
  260. *
  261. * //fromXposition- x coordinate from where animation should start
  262. * //toXPosition- x coordinate at which animation would end //fromYPosition-
  263. * y coordinate from where animation should start. //toYPosition- y
  264. * coordinate at which animation would end.
  265. *
  266. * //You can also set duration for the animation that means you can set for
  267. * how long the animation should last: transAnimation.setDuration(550);
  268. * //You can now apply the animation to a view
  269. * prompt.startAnimation(transAnimation);
  270. ********************************************************************/
  271. private void animateTop() {
  272. TranslateAnimation transAnimation = new TranslateAnimation(0, 0, 200, 0);
  273. transAnimation.setDuration(100);
  274. prompt.startAnimation(transAnimation);
  275. }
  276. private void animateBottomAnswer() {
  277. TranslateAnimation transAnimation = new TranslateAnimation(0, 0, -200,
  278. 0);
  279. transAnimation.setDuration(100);
  280. answer.startAnimation(transAnimation);
  281. // other.startAnimation(transAnimation);
  282. }
  283. private void animateBottomOther() {
  284. TranslateAnimation transAnimation = new TranslateAnimation(0, 0, -200,
  285. 0);
  286. transAnimation.setDuration(100);
  287. other.startAnimation(transAnimation);
  288. }
  289. private void animateLeft() {
  290. TranslateAnimation transAnimation = new TranslateAnimation(500, 0, 0, 0);
  291. transAnimation.setDuration(100);
  292. prompt.startAnimation(transAnimation);
  293. }
  294. private void animateRight() {
  295. TranslateAnimation transAnimation = new TranslateAnimation(-500, 0, 0,
  296. 0);
  297. transAnimation.setDuration(100);
  298. prompt.startAnimation(transAnimation);
  299. answer.startAnimation(transAnimation);
  300. other.startAnimation(transAnimation);
  301. }
  302. public void onClick(View v) {
  303. // if(v.getId() == R.id.advanceButton && okay.getText() == "done"){
  304. // Log.d(TAG, "okay button clicked ---> DONE");
  305. // doOkay();
  306. // }
  307. // Filter f = (Filter) v.getTag();
  308. // FilterFullScreenActivity.show(this, input, f);
  309. // switch (v.getId()) {
  310. // case R.id.advanceButton:
  311. // doAdvance();
  312. // break;
  313. // case R.id.okayButton:
  314. // Log.d(TAG, "okay button clicked ---> DONE");
  315. // doOkay();
  316. //
  317. // break;
  318. // case R.id.promptTextView:
  319. // case R.id.answerTextView:
  320. // case R.id.otherTextView:
  321. // Toast.makeText(this, "Item index: "+lp.currentIndex(),
  322. // Toast.LENGTH_LONG).show();
  323. // break;
  324. // default :
  325. // // doAdvance();
  326. // break;
  327. // }
  328. }
  329. void reportError(){
  330. Intent emailIntent = new Intent(Intent.ACTION_SEND);
  331. emailIntent.setType("message/rfc822");
  332. emailIntent.putExtra(Intent.EXTRA_EMAIL,
  333. new String[] { "xue@meadoweast.com" });
  334. emailIntent.putExtra(Intent.EXTRA_SUBJECT,
  335. "ERROR REPORT: ITEM INDEX : " + lp.currentIndex());
  336. emailIntent.putExtra(Intent.EXTRA_TEXT,
  337. "I am reporting an error from " + MainActivity.PACKAGE + " application with the following card :\n" + lp.prompt() + "\n"
  338. + lp.answer() + "\n" + lp.other());
  339. try {
  340. startActivity(Intent.createChooser(emailIntent, "Send Error Report"));
  341. } catch (android.content.ActivityNotFoundException ex) {
  342. Toast.makeText(this, "Item index: " + lp.currentIndex(),
  343. Toast.LENGTH_LONG).show();
  344. }
  345. }
  346. public boolean onLongClick(View v) {
  347. switch (v.getId()) {
  348. case R.id.promptTextView:
  349. case R.id.answerTextView:
  350. case R.id.otherTextView:
  351. Toast.makeText(this, "Sending Error Report",
  352. Toast.LENGTH_SHORT).show();
  353. reportError();
  354. break;
  355. }
  356. return true;
  357. }
  358. private void onSwipeTop() { // throws IllegalArgumentException,
  359. // SecurityException, IllegalStateException,
  360. // IOException {
  361. // TODO Auto-generated method stub
  362. Log.d(TAG, "onSwipeTop()");
  363. doOkay();
  364. }
  365. private void onSwipeBottom() {
  366. if (okay.getText().equals("done")) // to prevent swiping bottom when end
  367. // of deck reached
  368. return;
  369. // TODO Auto-generated method stub
  370. Log.d(TAG, "onSwipeBottom()");
  371. doAdvance();
  372. }
  373. private void onSwipeLeft() {
  374. if (okay.getText().equals("done")) // to prevent swiping left when end
  375. // of deck reached
  376. return;
  377. // TODO Auto-generated method stub
  378. Log.d(TAG, "onSwipeLeft()");
  379. // code from old doAdvance() function --> condition: (itemsShown == 3)
  380. if (itemsShown > 1) {
  381. animateLeft();
  382. lp.wrong();
  383. lp.next();
  384. clearContent();
  385. prompt.setText(lp.prompt());
  386. itemsShown = 1;
  387. status.setText(lp.deckStatus());
  388. okay.setText("show");
  389. playWrongSound();
  390. }
  391. }
  392. private void onSwipeRight() {
  393. // TODO Auto-generated method stub
  394. Log.d(TAG, "onSwipeRight()");
  395. okay.setText("show");
  396. if (lp.undo()) {
  397. animateRight();
  398. Log.d(TAG, "Undo action successful");
  399. clearContent();
  400. prompt.setText(lp.prompt());
  401. status.setText(lp.deckStatus());
  402. itemsShown = 1;
  403. } else {
  404. Log.d(TAG, "SHOULD SEE TOAST");
  405. Toast.makeText(this, "Cannot undo anymore", Toast.LENGTH_SHORT)
  406. .show();
  407. }
  408. }
  409. @Override
  410. public boolean onKeyDown(int keyCode, KeyEvent event) {
  411. if (keyCode == KeyEvent.KEYCODE_BACK) {
  412. Log.d(TAG, "llkj");
  413. new AlertDialog.Builder(this)
  414. .setIcon(android.R.drawable.ic_dialog_alert)
  415. .setTitle(R.string.quit)
  416. .setMessage(R.string.reallyQuit)
  417. .setPositiveButton(R.string.yes,
  418. new DialogInterface.OnClickListener() {
  419. public void onClick(DialogInterface dialog,
  420. int which) {
  421. LearnActivity.this.finish();
  422. }
  423. }).setNegativeButton(R.string.no, null).show();
  424. return true;
  425. } else {
  426. return super.onKeyDown(keyCode, event);
  427. }
  428. }
  429. class MyGestureDetector extends SimpleOnGestureListener { // imported
  430. // SimpleOnGestureListener
  431. @Override
  432. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
  433. float velocityY) {
  434. try {
  435. // Log.d("!", "e1 - e2 -> X " + Math.abs(e1.getX() -
  436. // e2.getX()));
  437. // Log.d("!", "e1 - e2 -> Y " + Math.abs(e1.getY() -
  438. // e2.getY()));
  439. // Log.d("!", "velocityX " + velocityX);
  440. // Log.d("!", "velocityY " + velocityY);
  441. if (Math.abs(velocityY) > Math.abs(velocityX)) {
  442. // if (Math.abs(e1.getY() - e2.getY()) >
  443. // SWIPE_MAX_OFF_PATH){
  444. if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE // ){
  445. && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
  446. onSwipeTop();
  447. } else // if(e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE
  448. // && Math.abs(velocityX) >
  449. // SWIPE_THRESHOLD_VELOCITY){
  450. {
  451. onSwipeBottom();
  452. }
  453. // return false;
  454. }
  455. // right to left swipe
  456. else if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE // ){
  457. && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
  458. // Toast.makeText(LearnActivity.this, "Left Swipe",
  459. // Toast.LENGTH_SHORT).show();
  460. onSwipeLeft();
  461. } else { // if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE){
  462. // && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
  463. // Toast.makeText(LearnActivity.this, "Right Swipe",
  464. // Toast.LENGTH_SHORT).show();
  465. onSwipeRight();
  466. }
  467. } catch (Exception e) {
  468. // nothing
  469. }
  470. return false;
  471. }
  472. }
  473. public boolean onTouch(View v, MotionEvent event) {
  474. // TODO Auto-generated method stub
  475. return false;
  476. }
  477. public void playCorrectSound(){
  478. if(soundFx==true){
  479. mPlayer = MediaPlayer.create(this, R.raw.correct);
  480. mPlayer.start();
  481. if (!mPlayer.isPlaying()){
  482. mPlayer.release();
  483. }
  484. }
  485. }
  486. public void playWrongSound(){
  487. if(soundFx==true){
  488. mPlayer = MediaPlayer.create(this, R.raw.wrong);
  489. mPlayer.start();
  490. }
  491. if (!mPlayer.isPlaying()){
  492. mPlayer.release();
  493. }
  494. }
  495. }