diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c39b002..66db6c5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -67,6 +67,16 @@ + + + + + + + diff --git a/app/src/main/assets/json/BasicTools.json b/app/src/main/assets/json/BasicTools.json index 6ffeb2e..77639f9 100644 --- a/app/src/main/assets/json/BasicTools.json +++ b/app/src/main/assets/json/BasicTools.json @@ -36,6 +36,13 @@ "en": "Base Converter" }, "activity": "com.fatapp.oxygentoolbox.tools.baseconverter.MainActivity" + }, + { + "text": { + "cn": "\u0055\u006e\u0069\u0063\u006f\u0064\u0065\u0020\u8f6c\u6362", + "en": "Unicode Converter" + }, + "activity": "com.fatapp.oxygentoolbox.tools.unicode.MainActivity" } ] } diff --git a/app/src/main/java/com/fatapp/oxygentoolbox/tools/unicode/MainActivity.java b/app/src/main/java/com/fatapp/oxygentoolbox/tools/unicode/MainActivity.java new file mode 100644 index 0000000..5e1da62 --- /dev/null +++ b/app/src/main/java/com/fatapp/oxygentoolbox/tools/unicode/MainActivity.java @@ -0,0 +1,152 @@ +package com.fatapp.oxygentoolbox.tools.unicode; + +import android.graphics.drawable.AnimatedVectorDrawable; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.fatapp.oxygentoolbox.R; +import com.fatapp.oxygentoolbox.util.ResourceUtil; +import com.fatapp.oxygentoolbox.util.tool.BaseActivityNormal; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.android.material.snackbar.Snackbar; + +import java.util.List; + +public class MainActivity extends BaseActivityNormal { + private final List BASE_LIST = List.of(ResourceUtil.getString(R.string.tool_unicode_text), + ResourceUtil.getString(R.string.tool_unicode_unicode), + ResourceUtil.getString(R.string.tool_unicode_ascii)); + + private int baseFrom = 0; + private int baseTo = 1; + private boolean isFromText = true; + + private TextView textViewBaseFrom; + private ImageView imageViewSwap; + private TextView textViewBaseTo; + private EditText editTextFrom; + private TextView textViewTo; + private ImageView imageViewConvert; + + private void initView() { + textViewBaseFrom = findViewById(R.id.text_view_base_from); + imageViewSwap = findViewById(R.id.image_view_swap); + textViewBaseTo = findViewById(R.id.text_view_base_to); + editTextFrom = findViewById(R.id.edit_text_from); + textViewTo = findViewById(R.id.text_view_to); + imageViewConvert = findViewById(R.id.image_view_convert); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + super.loadView(this, R.layout.activity_tool_unicode); + + initView(); + initChoose(); + initConverter(); + } + + private void initChoose() { + textViewBaseFrom.setOnClickListener(v -> new MaterialAlertDialogBuilder(this) + .setTitle(ResourceUtil.getString(R.string.tool_common_choose)) + .setItems(isFromText ? + List.of(BASE_LIST.get(0)).toArray(String[]::new) : + List.of(BASE_LIST.get(1), BASE_LIST.get(2)).toArray(String[]::new), + (dialog, which) -> { + textViewBaseFrom.setText(isFromText ? BASE_LIST.get(0) : BASE_LIST.get(which + 1)); + baseFrom = isFromText ? 0 : (which + 1); + if (textViewTo.getText().length() > 0) { + convert(); + } + }) + .show()); + textViewBaseTo.setOnClickListener(v -> new MaterialAlertDialogBuilder(this) + .setTitle(ResourceUtil.getString(R.string.tool_common_choose)) + .setItems(isFromText ? + List.of(BASE_LIST.get(1), BASE_LIST.get(2)).toArray(String[]::new): + List.of(BASE_LIST.get(0)).toArray(String[]::new), + (dialog, which) -> { + textViewBaseTo.setText(isFromText ? BASE_LIST.get(which + 1) : BASE_LIST.get(0)); + baseTo = isFromText ? (which + 1) : 0; + if (textViewTo.getText().length() > 0) { + convert(); + } + }) + .show()); + imageViewSwap.setOnClickListener(v -> { + AnimatedVectorDrawable animatedVectorDrawable = (AnimatedVectorDrawable) imageViewSwap.getDrawable(); + animatedVectorDrawable.start(); + isFromText = !isFromText; + { + int temp = baseFrom; + baseFrom = baseTo; + baseTo = temp; + } + { + String temp = textViewBaseFrom.getText().toString(); + textViewBaseFrom.setText(textViewBaseTo.getText()); + textViewBaseTo.setText(temp); + } + editTextFrom.setText(null); + textViewTo.setText(null); + }); + } + + private void initConverter() { + editTextFrom.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + imageViewConvert.setEnabled(s.length() != 0); + } + + @Override + public void afterTextChanged(Editable s) { + + } + }); + textViewTo.setOnFocusChangeListener((view, b) -> ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(editTextFrom.getWindowToken(), 0)); + imageViewConvert.setEnabled(false); + imageViewConvert.setOnClickListener(view -> convert()); + } + + private void convert() { + ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(editTextFrom.getWindowToken(), 0); + switch (baseFrom) { + case 0 -> { + switch (baseTo) { + case 1 -> + textViewTo.setText(Utils.stringToUnicode(editTextFrom.getText().toString())); + case 2 -> + textViewTo.setText(Utils.stringToAscii(editTextFrom.getText().toString())); + } + } + case 1 -> { + try { + textViewTo.setText(Utils.unicodeToString(editTextFrom.getText().toString())); + } catch (Exception e) { + Snackbar.make(getConstraintLayoutRoot(), ResourceUtil.getString(R.string.tool_unicode_illegal_input), Snackbar.LENGTH_LONG).show(); + } + } + case 2 -> { + try { + textViewTo.setText(Utils.asciiToString(editTextFrom.getText().toString())); + } catch (Exception e) { + Snackbar.make(getConstraintLayoutRoot(), ResourceUtil.getString(R.string.tool_unicode_illegal_input), Snackbar.LENGTH_LONG).show(); + } + } + } + } +} diff --git a/app/src/main/java/com/fatapp/oxygentoolbox/tools/unicode/Utils.java b/app/src/main/java/com/fatapp/oxygentoolbox/tools/unicode/Utils.java new file mode 100644 index 0000000..09724fa --- /dev/null +++ b/app/src/main/java/com/fatapp/oxygentoolbox/tools/unicode/Utils.java @@ -0,0 +1,52 @@ +package com.fatapp.oxygentoolbox.tools.unicode; + +import java.util.StringJoiner; + +public class Utils { + public static String stringToAscii(String value) { + StringJoiner stringJoiner = new StringJoiner(";&#", "&#", ";"); + char[] chars = value.toCharArray(); + for (char aChar : chars) { + stringJoiner.add(String.valueOf((int) aChar)); + } + return stringJoiner.toString(); + } + + public static String asciiToString(String value) throws Exception { + if (!value.startsWith("&#") || !value.endsWith(";")) { + throw new Exception(); + } + + StringBuilder stringBuffer = new StringBuilder(); + value = value.substring(2); + value = value.substring(0, value.length()-1); + String[] chars = value.split(";&#"); + for (String aChar : chars) { + stringBuffer.append((char) Integer.parseInt(aChar)); + } + return stringBuffer.toString(); + } + + public static String stringToUnicode(String value) { + StringJoiner stringJoiner = new StringJoiner("\\u", "\\u", ""); + char[] chars = value.toCharArray(); + for (char aChar : chars) { + stringJoiner.add(Integer.toHexString(aChar)); + } + return stringJoiner.toString(); + } + + public static String unicodeToString(String value) throws Exception { + if (!value.startsWith("\\u")) { + throw new Exception(); + } + + StringBuilder stringBuffer = new StringBuilder(); + value = value.substring(2); + String[] chars = value.split("\\\\u"); + for (String aChar : chars) { + stringBuffer.append((char) Integer.parseInt(aChar, 16)); + } + return stringBuffer.toString(); + } +} diff --git a/app/src/main/res/drawable/ic_tool_baseconverter_convert.xml b/app/src/main/res/drawable/ic_tool_arrow_down.xml similarity index 100% rename from app/src/main/res/drawable/ic_tool_baseconverter_convert.xml rename to app/src/main/res/drawable/ic_tool_arrow_down.xml diff --git a/app/src/main/res/layout/activity_tool_baseconverter.xml b/app/src/main/res/layout/activity_tool_baseconverter.xml index e17cfea..74820d9 100644 --- a/app/src/main/res/layout/activity_tool_baseconverter.xml +++ b/app/src/main/res/layout/activity_tool_baseconverter.xml @@ -30,7 +30,7 @@ android:id="@+id/image_view_swap" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:contentDescription="Swap" + android:contentDescription="@string/tool_common_swap" android:padding="@dimen/tool_baseconverter_clickable_padding" android:src="@drawable/animation_swap_horizon" /> @@ -54,7 +54,7 @@ android:autofillHints="text" android:background="@drawable/background_radius" android:gravity="start|top" - android:hint="@string/tool_baseconverter_please_enter_text" + android:hint="@string/tool_common_please_enter_text" android:inputType="text" android:maxLength="850" android:paddingHorizontal="@dimen/tool_baseconverter_edit_text_view_padding" @@ -96,10 +96,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" - android:contentDescription="Convert" + android:contentDescription="@string/tool_common_convert" android:focusable="true" android:foreground="@drawable/foreground_ripple" - android:src="@drawable/ic_tool_baseconverter_convert" + android:src="@drawable/ic_tool_arrow_down" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/layout/activity_tool_translation.xml b/app/src/main/res/layout/activity_tool_translation.xml index b05e1d8..9ea0bde 100644 --- a/app/src/main/res/layout/activity_tool_translation.xml +++ b/app/src/main/res/layout/activity_tool_translation.xml @@ -30,7 +30,7 @@ android:id="@+id/image_view_swap" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:contentDescription="Swap" + android:contentDescription="@string/tool_common_swap" android:padding="@dimen/tool_translation_clickable_padding" android:src="@drawable/animation_swap_horizon" /> @@ -54,7 +54,7 @@ android:autofillHints="text" android:background="@drawable/background_radius" android:gravity="start|top" - android:hint="@string/tool_translation_please_enter_text" + android:hint="@string/tool_common_please_enter_text" android:inputType="textMultiLine" android:maxLength="850" android:paddingHorizontal="@dimen/tool_translation_edit_text_view_padding" @@ -96,7 +96,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" - android:contentDescription="Translate" + android:contentDescription="@string/tool_common_translation" android:focusable="true" android:foreground="@drawable/foreground_ripple" android:src="@drawable/ic_tool_translation_translate" diff --git a/app/src/main/res/layout/activity_tool_unicode.xml b/app/src/main/res/layout/activity_tool_unicode.xml new file mode 100644 index 0000000..808e863 --- /dev/null +++ b/app/src/main/res/layout/activity_tool_unicode.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fold_layout_button.xml b/app/src/main/res/layout/fold_layout_button.xml index f47d43f..b74f20e 100644 --- a/app/src/main/res/layout/fold_layout_button.xml +++ b/app/src/main/res/layout/fold_layout_button.xml @@ -4,5 +4,6 @@ xmlns:android="http://schemas.android.com/apk/res/android">