- •Курсовая работа
- •3 Разработка основных модулей приложения 7
- •1. Техническое Задание
- •2.Описание и обоснование
- •2.1 Выбор технологии разработки приложение
- •3 Разработка основных модулей приложения
- •3.1 Модуль работы с сервисом перевода текста
- •3.2 Модуль работы с сервисом словаря
- •3.3 Модуль работы с базой данных
- •4 Разработка основного функционала
4 Разработка основного функционала
Основной функционал приложение разбит на 3 составляющие.
Переводчик текста
История передов и избранные переводы
Настройки переводов
Каждое окно приложение сделано в виде отдельного фрагмента переключение между которыми происходит по средствам свайпа либо же нажатиями клавиш.
Фрагмент (класс Fragment) - представляет поведение или часть пользовательского интерфейса в операции (класс Activity). Разработчик может объединить несколько фрагментов в одну операцию для построения многопанельного пользовательского интерфейса и повторного использования фрагмента в нескольких операциях. Фрагмент можно рассматривать как модульную часть операции. Такая часть имеет свой жизненный цикл и самостоятельно обрабатывает события ввода. Кроме того, ее можно добавить или удалить непосредственно во время выполнения операции. Это нечто вроде вложенной операции, которую можно многократно использовать в различных операциях.
Листинг фрагмента перевода текста:
* Метод перевода текста с последующим отображением * @param text Текст для перевода * @param fromLang С какого языка перевод * @param toLang На какой язык перевод * @param isDictionaryWord Нужно ли заменить текст в поле ввода * */ public void translate(final String text, final String fromLang, final String toLang, boolean isDictionaryWord) { /** Нужно ли показывать словарь */ final boolean showDictionary = getPreferences().getBoolean("showDictionary",true); /** Офлайн перевод */ final boolean offlineTranslate = getPreferences().getBoolean("offlineTranslate",true); /** Проверка текста перевода на пустату */ if(TextUtils.isEmpty(text)) { /** Скрываю frame с результатом перевода и словарем */ dictionatyResultFrame.setVisibility(View.GONE); translateResultFrame.setVisibility(View.GONE); return; } /** Язык перевода */ final String translateLang = fromLang + "-" + toLang; /** Замена текста в поле ввода */ if(isDictionaryWord) { editText.removeTextChangedListener(editTextWatcher); editText.setTextKeepState(text); editText.addTextChangedListener(editTextWatcher); clearText.setVisibility((text.length() > 0) ? View.VISIBLE : View.INVISIBLE); } /** Смена языков перевода spinners */ sFirst.setOnItemSelectedListener(null); sSecond.setOnItemSelectedListener(null); sFirst.setSelection(Arrays.asList(Translator.langsCode).indexOf(fromLang),false); sSecond.setSelection(Arrays.asList(Translator.langsCode).indexOf(toLang),false); sFirst.setOnItemSelectedListener(onSpinnerChanged); sSecond.setOnItemSelectedListener(onSpinnerChanged); /** Скрываю frame с результатом перевода и словарем */ dictionatyResultFrame.setVisibility(View.GONE); translateResultFrame.setVisibility(View.GONE); /** Включаю ProgressBar */ translateProgressBar.setVisibility(View.VISIBLE); /** Офлайн перевод */ if(offlineTranslate) { /** Проверяем в БД перевод такого текста и языка */ ArrayList<TranslateResultModel> dbTranslate = dataBaseHelper.getTranslate(text, translateLang); /** Если пеервод встечается, то выводим и делаем запрос на словарь * Словарь в БД не хранится * */ if (dbTranslate.size() != 0) { translateProgressBar.setVisibility(View.GONE); translateResultFrame.setVisibility(View.VISIBLE); translateText.setText(dbTranslate.get(0).to); translateResultFrame.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.move)); if(showDictionary) dictionary(text, fromLang, toLang); return; } } /** Онлайн перевод */ translator.translate(text, translateLang, new Response.Listener<String>() { @Override public void onResponse(String response) { try { /** Вытаксиваем результат перевода */ JSONObject jObject = new JSONObject(response); JSONArray jArray = jObject.getJSONArray("text"); final String translatedText = jArray.getString(0); final String origText = text; /** Добавляю в БД результат пеервода */ dataBaseHelper.insert(new TranslateResultModel(origText,translatedText,translateLang,false)); /** Обновляю историю переводов */ ((MainActivity)getActivity()).getHistoryFragment().updateHistoryList(); /** Включаю фреймы */ translateResultFrame.setVisibility(View.VISIBLE); translateProgressBar.setVisibility(View.GONE); /** Ставлю текст перевода */ translateText.setText(translatedText); translateResultFrame.startAnimation(AnimationUtils.loadAnimation(getContext(),R.anim.move)); if(showDictionary) dictionary(text,fromLang,toLang); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { /** В случае ошибки ответа */ if(error.networkResponse != null) translateText.setText(getResources().getString(R.string.failedTranslateText) + "\n" + getResources().getString(R.string.errorCode) + error.networkResponse.statusCode); else translateText.setText(getResources().getString(R.string.failedTranslateText) + "\n" + getResources().getString(R.string.checkInternet)); translateProgressBar.setVisibility(View.GONE); translateResultFrame.setVisibility(View.VISIBLE); translateResultFrame.startAnimation(AnimationUtils.loadAnimation(getContext(),R.anim.move)); } }); } /** * Метод получения словаря, с последующим отображением * @param text Текст для перевода * @param fromLang С какого языка перевод * @param toLang На какой язык перевод * */ public void dictionary(final String text, final String fromLang, final String toLang) { /** Язык перевода */ final String translateLang = fromLang + "-" + toLang; /** Скрываю фрейм словаря */ dictionatyResultFrame.setVisibility(View.GONE); /** Запрос к словарю */ dictionary.getWords(text, translateLang, new Response.Listener<String>() { @Override public void onResponse(String response) { /** Создание SpannableString * Слова будут окрашены и начнут нажиматься * */ SpannableString dict = dictionary.getDictionarySpannableString(response,fromLang,toLang); /** Проверка на пустую строку */ if(!TextUtils.isEmpty(dict.toString())) { dictionatyResultFrame.setVisibility(View.VISIBLE); dictionaryText.setText(dict); dictionatyResultFrame.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.move)); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { /** Ошибки словаря не выводятся */ } }); } @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.translator_main, container, false); ((MainActivity)getActivity()).translatorFragment = this; translator = ((MainActivity)getActivity()).getTranslator(); dictionary = ((MainActivity)getActivity()).getDictionary(); sFirst = (Spinner) rootView.findViewById(R.id.spinnerFromLang); sSecond = (Spinner) rootView.findViewById(R.id.spinnerToLang); translateText = (TextView)rootView.findViewById(R.id.translatedText); dictionaryText = (TextView)rootView.findViewById(R.id.dictionaryText); dictionaryText.setMovementMethod(LinkMovementMethod.getInstance()); translateResultFrame = (FrameLayout) rootView.findViewById(R.id.translateResult); dictionatyResultFrame = (FrameLayout) rootView.findViewById(R.id.dictionaryResult); translateProgressBar = (ProgressBar) rootView.findViewById(R.id.translateProgressBar); TextView translatedByYandex = (TextView)rootView.findViewById(R.id.translatedByYandex); translatedByYandex.setText(Html.fromHtml(getResources().getString(R.string.translatedByYandex))); translatedByYandex.setMovementMethod(LinkMovementMethod.getInstance()); switchLang = (ImageButton) rootView.findViewById(R.id.switchLang); clearText = (ImageButton) rootView.findViewById(R.id.clearText); ImageButton openFullscreen = (ImageButton) rootView.findViewById(R.id.openFullscreen); openFullscreen.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getContext(), TextReaderActivity.class); intent.putExtra("text",translateText.getText().toString()); startActivity(intent); } }); /** Листеер на очистку поля ввода */ clearText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { editText.setText(""); } }); /** Листеер на смену языков местами */ switchLang.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /** Анимации */ switchLang.setRotation(0); switchLang.animate().rotation(180).setDuration(500); sFirst.animate().alpha(0).setDuration(300); sSecond.animate().alpha(0).setDuration(300); } }); editText = (EditText)rootView.findViewById(R.id.editText); /** TextWatcher */ editTextWatcher = new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { /** Включаем скопку очистки поля если поле не пустое */ clearText.setVisibility((s.length() > 0) ? View.VISIBLE : View.INVISIBLE); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } /** Наймер на задержку после ввода текста * Лучше наверно сделать через Handler */ private Timer timer=new Timer(); /** Время через которое начнется перевод текста, после окончания ввода */ private final long DELAY = 1000; @Override public void afterTextChanged(final Editable s) { if(s.toString().trim().length()>0) { timer.cancel(); timer = new Timer(); timer.schedule( new TimerTask() { @Override public void run() { /** В UI потоке вызываем метод перевода текста */ getActivity().runOnUiThread(new Runnable() { @Override public void run() { translate(editText.getText().toString(), Translator.langsCode[sFirst.getSelectedItemPosition()], Translator.langsCode[sSecond.getSelectedItemPosition()],false); } }); } }, DELAY ); } } }; /** Додавляем листенер */ editText.addTextChangedListener(editTextWatcher); ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource( getContext(), R.array.langs, R.layout.spinner_lang_item); sFirst.setAdapter(adapter); sSecond.setAdapter(adapter); onSpinnerChanged = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { translate(editText.getText().toString(), Translator.langsCode[sFirst.getSelectedItemPosition()], Translator.langsCode[sSecond.getSelectedItemPosition()],false); } @Override public void onNothingSelected(AdapterView<?> parent) {} }); /** Установка начальных языков перевода */ String sysLang = Locale.getDefault().getLanguage(); switch (sysLang) { case "en": sFirst.setSelection(Arrays.asList(Translator.langsCode).indexOf("en")); sSecond.setSelection(Arrays.asList(Translator.langsCode).indexOf("ru")); break; case "ru": sFirst.setSelection(Arrays.asList(Translator.langsCode).indexOf("ru")); sSecond.setSelection(Arrays.asList(Translator.langsCode).indexOf("en")); break; default: sFirst.setSelection(Arrays.asList(Translator.langsCode).indexOf("auto")); sSecond.setSelection(Arrays.asList(Translator.langsCode).indexOf("en")); break; } return rootView; } }
Листинг фрагмента с историей и избранными переводами:
public static HistoryFragment newInstance() {
return new HistoryFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.history_main, container, false);
dbHelper = ((MainActivity)getActivity()).getDbHelper();
((MainActivity)getActivity()).historyFragment = this;
noTranslateHistory = (LinearLayout) rootView.findViewById(R.id.noTranslateHistory);
noHistoryText = (TextView) rootView.findViewById(R.id.noTranslateHistoryText);
clearHistory = (ImageButton) rootView.findViewById(R.id.clearHistory);
/** Вкладки для переключения межно историей и избранным */
mTabLayout = (TabLayout) rootView.findViewById(R.id.historyTab);
mTabLayout.addTab(mTabLayout.newTab().setText(R.string.history));
mTabLayout.addTab(mTabLayout.newTab().setText(R.string.favorite));
/** Листенер на смену вкладок */
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
/** Устанавливаю текст с SearchView
* Просто мелочь...
* */
switch (tab.getPosition()) {
case 0:
searchView.setQueryHint(getResources().getString(R.string.searchInHistory));
break;
case 1:
searchView.setQueryHint(getResources().getString(R.string.searchInFavorite));
break;
default:
ListView lv = (ListView)rootView.findViewById(R.id.searchList);
adapter = new HistoryArrayAdapter(getContext());
lv.setAdapter(adapter);
searchView = (SearchView)rootView.findViewById(R.id.searchView);
/** Начальное обновления списка */
updateHistoryList();
return rootView;
}
public void updateHistoryList()
{
/** Очищаю список*/
adapter.clear();
/** Добавляю в список значения из БД */
adapter.addAll(dbHelper.getHistory(searchView.getQuery().toString(),
(mTabLayout.getSelectedTabPosition() == 1)));
/** Обновляю в UI*/
adapter.notifyDataSetChanged();
/** Если в БД есть значения, то включаю кнопку очистки истории */
clearHistory.setVisibility((dbHelper.dbCount() > 0) ? View.VISIBLE : View.GONE);
/** Если есть элементы в БД */
if(adapter.getCount() > 0)
noTranslateHistory.setVisibility(View.GONE);
else
{
noTranslateHistory.setVisibility(View.VISIBLE);
noHistoryText.setText((mTabLayout.getSelectedTabPosition() == 0) ?
getResources().getString(R.string.noTranslateHistory) :
getResources().getString(R.string.noFavorites));
}
Заключение
Мною было разработано полноценное приложение в точности по ТЗ имеющее полный функционал переводчика включая:
Онлайн/оффлайн перевод текста
Показа словаря
История и избранные переводы
В качестве референса для дизайна использовалось официальное приложение Yandex Переводчик.
Также использовались технологии API Yandex Translate и API Yandex Dictionary через которые был реализован перевод текста и показ словаря.
Для сетевых запросов использовалась библиотека Volley.
Поддержка старых версий ОС Android реализована через библиотеку Support Library
Список литературы
IDE Android Studio -https://ru.wikipedia.org/wiki/Android_Studio
Сервис перевода текста API Yandex Translate - https://tech.yandex.ru/translate/
Yandex Mobilization - https://academy.yandex.ru/events/mobdev/msk-2017/
Сервис словаря API Yandex Dictionary - https://tech.yandex.ru/dictionary/
Библиотека сетевых запросов Volley - https://developer.android.com/training/volley/index.html
Фрагменты в ОС Android - https://developer.android.com/guide/components/fragments.html?hl=ru
