/**************************************************************************************** * Copyright (c) 2013 Bibek Shrestha <bibekshrestha@gmail.com> * * Copyright (c) 2013 Zaur Molotnikov <qutorial@gmail.com> * * Copyright (c) 2013 Nicolas Raoul <nicolas.raoul@gmail.com> * * Copyright (c) 2013 Flavio Lerda <flerda@gmail.com> * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 3 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see <http://www.gnu.org/licenses/>. * ****************************************************************************************/ package com.ichi2.anki.multimediacard.activity; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import com.google.gson.Gson; import com.ichi2.anki.AnkiDroidApp; import com.ichi2.anki.R; import com.ichi2.anki.multimediacard.glosbe.json.Meaning; import com.ichi2.anki.multimediacard.glosbe.json.Phrase; import com.ichi2.anki.multimediacard.glosbe.json.Response; import com.ichi2.anki.multimediacard.glosbe.json.Tuc; import com.ichi2.anki.multimediacard.language.LanguagesListerGlosbe; import com.ichi2.anki.runtimetools.TaskOperations; import com.ichi2.anki.web.HttpFetcher; import com.ichi2.async.Connection; import com.ichi2.libanki.Utils; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Locale; /** * Activity used now with Glosbe.com to enable translation of words. */ public class TranslationActivity extends FragmentActivity implements DialogInterface.OnClickListener, OnCancelListener { private static final String BUNDLE_KEY_SHUT_OFF = "key.multimedia.shut.off"; // Something to translate public static final String EXTRA_SOURCE = "translation.activity.extra.source"; // Translated result public static final String EXTRA_TRANSLATION = "translation.activity.extra.translation"; String mSource; String mTranslation; private LanguagesListerGlosbe mLanguageLister; private Spinner mSpinnerFrom; private Spinner mSpinnerTo; private ProgressDialog progressDialog = null; private String mWebServiceAddress; private ArrayList<String> mPossibleTranslations; private String mLangCodeTo; private BackgroundPost mTranslationLoadPost = null; private void finishCancel() { Intent resultData = new Intent(); setResult(RESULT_CANCELED, resultData); finish(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { boolean b = savedInstanceState.getBoolean(BUNDLE_KEY_SHUT_OFF, false); if (b) { finishCancel(); return; } } setContentView(R.layout.activity_translation); try { mSource = getIntent().getExtras().getString(EXTRA_SOURCE); } catch (Exception e) { mSource = ""; } // If translation fails this is a default - source will be returned. mTranslation = mSource; LinearLayout linearLayout = (LinearLayout) findViewById(R.id.MainLayoutInTranslationActivity); TextView tv = new TextView(this); tv.setText(getText(R.string.multimedia_editor_trans_poweredglosbe)); linearLayout.addView(tv); TextView tvFrom = new TextView(this); tvFrom.setText(getText(R.string.multimedia_editor_trans_from)); linearLayout.addView(tvFrom); mLanguageLister = new LanguagesListerGlosbe(this); mSpinnerFrom = new Spinner(this); ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mLanguageLister.getLanguages()); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mSpinnerFrom.setAdapter(adapter); linearLayout.addView(mSpinnerFrom); TextView tvTo = new TextView(this); tvTo.setText(getText(R.string.multimedia_editor_trans_to)); linearLayout.addView(tvTo); mSpinnerTo = new Spinner(this); ArrayAdapter<String> adapterTo = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mLanguageLister.getLanguages()); adapterTo.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mSpinnerTo.setAdapter(adapterTo); linearLayout.addView(mSpinnerTo); final SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext()); // Try to set spinner value to last selected position String fromLang = preferences.getString("translatorLastLanguageFrom", ""); String toLang = preferences.getString("translatorLastLanguageTo", ""); mSpinnerFrom.setSelection(getSpinnerIndex(mSpinnerFrom, fromLang)); mSpinnerTo.setSelection(getSpinnerIndex(mSpinnerTo, toLang)); // Setup button Button btnDone = new Button(this); btnDone.setText(getText(R.string.multimedia_editor_trans_translate)); btnDone.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // Remember currently selected language String fromLang = mSpinnerFrom.getSelectedItem().toString(); String toLang = mSpinnerTo.getSelectedItem().toString(); preferences.edit().putString("translatorLastLanguageFrom", fromLang).commit(); preferences.edit().putString("translatorLastLanguageTo", toLang).commit(); // Get translation translate(); } }); linearLayout.addView(btnDone); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_translation, menu); return true; } private class BackgroundPost extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... params) { return HttpFetcher.fetchThroughHttp(mWebServiceAddress); } @Override protected void onPostExecute(String result) { progressDialog.dismiss(); mTranslation = result; showPickTranslationDialog(); } } protected void translate() { if(!Connection.isOnline()) { showToast(gtxt(R.string.network_no_connection)); return; } progressDialog = ProgressDialog.show(this, getText(R.string.multimedia_editor_progress_wait_title), getText(R.string.multimedia_editor_trans_translating_online), true, false); progressDialog.setCancelable(true); progressDialog.setOnCancelListener(this); mWebServiceAddress = computeAddress(); try { mTranslationLoadPost = new BackgroundPost(); mTranslationLoadPost.execute(); } catch (Exception e) { progressDialog.dismiss(); showToast(getText(R.string.multimedia_editor_something_wrong)); } } private String computeAddress() { String address = "http://glosbe.com/gapi/translate?from=FROMLANG&dest=TOLANG&format=json&phrase=SOURCE&pretty=true"; String strFrom = mSpinnerFrom.getSelectedItem().toString(); // Conversion to iso, lister created before. String langCodeFrom = mLanguageLister.getCodeFor(strFrom); String strTo = mSpinnerTo.getSelectedItem().toString(); mLangCodeTo = mLanguageLister.getCodeFor(strTo); String query; try { query = URLEncoder.encode(mSource, "utf-8"); } catch (UnsupportedEncodingException e) { query = mSource.replace(" ", "%20"); } address = address.replaceAll("FROMLANG", langCodeFrom).replaceAll("TOLANG", mLangCodeTo) .replaceAll("SOURCE", query); return address; } private String gtxt(int id) { return getText(id).toString(); } private void showToastLong(CharSequence text) { int duration = Toast.LENGTH_LONG; Toast toast = Toast.makeText(this, text, duration); toast.show(); } private void showPickTranslationDialog() { if (mTranslation.startsWith("FAILED")) { returnFailure(getText(R.string.multimedia_editor_trans_getting_failure).toString()); return; } Gson gson = new Gson(); Response resp = gson.fromJson(mTranslation, Response.class); if (resp == null) { returnFailure(getText(R.string.multimedia_editor_trans_getting_failure).toString()); return; } if (!resp.getResult().contentEquals("ok")) { if (!mSource.toLowerCase(Locale.getDefault()).contentEquals(mSource)) { showToastLong(gtxt(R.string.multimedia_editor_word_search_try_lower_case)); } returnFailure(getText(R.string.multimedia_editor_trans_getting_failure).toString()); return; } mPossibleTranslations = parseJson(resp, mLangCodeTo); if (mPossibleTranslations.size() == 0) { if (!mSource.toLowerCase(Locale.getDefault()).contentEquals(mSource)) { showToastLong(gtxt(R.string.multimedia_editor_word_search_try_lower_case)); } returnFailure(getText(R.string.multimedia_editor_error_word_not_found).toString()); return; } PickStringDialogFragment fragment = new PickStringDialogFragment(); fragment.setChoices(mPossibleTranslations); fragment.setOnclickListener(this); fragment.setTitle(getText(R.string.multimedia_editor_trans_pick_translation).toString()); fragment.show(this.getSupportFragmentManager(), "pick.translation"); } private static ArrayList<String> parseJson(Response resp, String languageCodeTo) { ArrayList<String> res = new ArrayList<>(); /* * The algorithm below includes the parsing of glosbe results. Glosbe.com returns a list of different phrases in * source and destination languages. This is done, probably, to improve the reader's understanding. We leave * here only the translations to the destination language. */ List<Tuc> tucs = resp.getTuc(); if (tucs == null) { return res; } String desiredLang = LanguagesListerGlosbe.requestToResponseLangCode(languageCodeTo); for (Tuc tuc : tucs) { if (tuc == null) { continue; } List<Meaning> meanings = tuc.getMeanings(); if (meanings != null) { for (Meaning meaning : meanings) { if (meaning == null) { continue; } if (meaning.getLanguage() == null) { continue; } if (meaning.getLanguage().contentEquals(desiredLang)) { String unescappedString = Utils.unescape(meaning.getText()); res.add(unescappedString); } } } Phrase phrase = tuc.getPhrase(); if (phrase != null) { if (phrase.getLanguage() == null) { continue; } if (phrase.getLanguage().contentEquals(desiredLang)) { String unescappedString = Utils.unescape(phrase.getText()); res.add(unescappedString); } } } return res; } private void returnTheTranslation() { Intent resultData = new Intent(); resultData.putExtra(EXTRA_TRANSLATION, mTranslation); setResult(RESULT_OK, resultData); finish(); } private void returnFailure(String explanation) { showToast(explanation); setResult(RESULT_CANCELED); dismissCarefullyProgressDialog(); finish(); } private void showToast(CharSequence text) { int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(this, text, duration); toast.show(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(BUNDLE_KEY_SHUT_OFF, true); } @Override public void onClick(DialogInterface dialog, int which) { mTranslation = mPossibleTranslations.get(which); returnTheTranslation(); } @Override public void onCancel(DialogInterface dialog) { stopWorking(); } private void stopWorking() { TaskOperations.stopTaskGracefully(mTranslationLoadPost); dismissCarefullyProgressDialog(); } @Override protected void onPause() { super.onPause(); stopWorking(); } private void dismissCarefullyProgressDialog() { try { if (progressDialog != null) { if (progressDialog.isShowing()) { progressDialog.dismiss(); } } } catch (Exception e) { // nothing is done intentionally } } private int getSpinnerIndex(Spinner spinner, String myString){ int index = 0; for (int i=0;i<spinner.getCount();i++){ if (spinner.getItemAtPosition(i).equals(myString)){ index = i; } } return index; } }