diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..9181204 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/icon.png b/res/drawable/icon.png new file mode 100644 index 0000000..6e851aa Binary files /dev/null and b/res/drawable/icon.png differ diff --git a/res/layout/about.xml b/res/layout/about.xml new file mode 100644 index 0000000..e01a830 --- /dev/null +++ b/res/layout/about.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/res/layout/main.xml b/res/layout/main.xml new file mode 100644 index 0000000..d10ec89 --- /dev/null +++ b/res/layout/main.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + diff --git a/res/values/arrays.xml b/res/values/arrays.xml new file mode 100644 index 0000000..842279e --- /dev/null +++ b/res/values/arrays.xml @@ -0,0 +1,79 @@ + + + + Adam + Boy + Charlie + David + Edward + Frank + George + Henry + Ida + John + King + Lincoln + Mary + Nora + Ocean + Paul + Queen + Robert + Sam + Tom + Union + Victor + William + X-Ray + Young + Zebra + Zero + One + Two + Three + Four + Five + Six + Seven + Eight + Niner + + + Alpha + Bravo + Charlie + Delta + Echo + Foxtrot + Golf + Hotel + India + Juliet + Kilo + Lima + Mike + November + Oscar + Papa + Quebec + Romeo + Sierra + Tango + Uniform + Victor + Whiskey + X-Ray + Yankee + Zulu + Zero + One + Two + Three + Four + Five + Six + Seven + Eight + Nine (Niner) + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..b71656e --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,18 @@ + + + SpellIt + Spell It! + Tap to continue... + Tap to repeat... + Start typing for history... + Please type something... + NATO Phonetic + G as in Google + © 2008 Erik C. Thauvin\nAll Rights Reserved\n\nerik@thauvin.net\n\nhttp://mobile.thauvin.net + About + OK + Cancel + as in + <space> + <done> + diff --git a/screenshots/1.psd b/screenshots/1.psd new file mode 100644 index 0000000..d0c810e Binary files /dev/null and b/screenshots/1.psd differ diff --git a/screenshots/2.psd b/screenshots/2.psd new file mode 100644 index 0000000..e3dc34e Binary files /dev/null and b/screenshots/2.psd differ diff --git a/screenshots/3.psd b/screenshots/3.psd new file mode 100644 index 0000000..aecabc1 Binary files /dev/null and b/screenshots/3.psd differ diff --git a/screenshots/spellit.gif b/screenshots/spellit.gif new file mode 100644 index 0000000..3048c28 Binary files /dev/null and b/screenshots/spellit.gif differ diff --git a/sign.bat b/sign.bat new file mode 100644 index 0000000..6809692 --- /dev/null +++ b/sign.bat @@ -0,0 +1,10 @@ +@echo off +"%JAVA_HOME%\bin\jarsigner" -verbose -keystore "%USERPROFILE%\personal\android.keystore" "%1" android +if errorlevel 1 goto ERROR +"%JAVA_HOME%\bin\jarsigner" -verify "%1" +if errorlevel 1 goto ERROR +goto DONE +:ERROR +@pause +:DONE +@echo on \ No newline at end of file diff --git a/src/net/thauvin/erik/android/spellit/R.java b/src/net/thauvin/erik/android/spellit/R.java new file mode 100644 index 0000000..ac67d21 --- /dev/null +++ b/src/net/thauvin/erik/android/spellit/R.java @@ -0,0 +1,48 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package net.thauvin.erik.android.spellit; + +public final class R { + public static final class array { + public static final int alphabet=0x7f040000; + public static final int nato_alphabet=0x7f040001; + } + public static final class attr { + } + public static final class drawable { + public static final int icon=0x7f020000; + } + public static final class id { + public static final int about_text_fld=0x7f060000; + public static final int main_entry_fld=0x7f060001; + public static final int main_result_fld=0x7f060003; + public static final int main_spell_btn=0x7f060002; + public static final int main_tap_lbl=0x7f060004; + } + public static final class layout { + public static final int about=0x7f030000; + public static final int main=0x7f030001; + } + public static final class string { + public static final int about_menu_txt=0x7f050009; + public static final int about_txt=0x7f050008; + public static final int alert_dialog_cancel=0x7f05000b; + public static final int alert_dialog_ok=0x7f05000a; + public static final int app_name=0x7f050000; + public static final int as_in_txt=0x7f05000c; + public static final int done_txt=0x7f05000e; + public static final int main_entry_err_txt=0x7f050005; + public static final int main_entry_hint_txt=0x7f050004; + public static final int main_spell_btn_txt=0x7f050001; + public static final int main_tap_lbl_repeat_txt=0x7f050003; + public static final int main_tap_lbl_txt=0x7f050002; + public static final int nato_menu_txt=0x7f050006; + public static final int sample_txt=0x7f050007; + public static final int space_txt=0x7f05000d; + } +} diff --git a/src/net/thauvin/erik/android/spellit/SpellIt.java b/src/net/thauvin/erik/android/spellit/SpellIt.java new file mode 100644 index 0000000..ae52834 --- /dev/null +++ b/src/net/thauvin/erik/android/spellit/SpellIt.java @@ -0,0 +1,445 @@ +/* + * @(#)SpellIt.java + * + * Copyright (c) 2008, Erik C. Thauvin (http://erik.thauvin.net/) + * 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 authors 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 OWNER 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. + * + * $Id$ + * + */ +package net.thauvin.erik.android.spellit; + +import java.util.ArrayList; +import java.util.List; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.text.ClipboardManager; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +/** + * SpellIt is a alphabet speller for Android. + * + * @author Erik C. Thauvin + * @version $Revision$, $Date$ + * @created Oct 30, 2008 + * @since 1.0 + */ +public class SpellIt extends Activity +{ + private static final int MAX_HISTORY_SIZE = 15; + private static final int MENU_ABOUT = 0; + private static final int MENU_NATO = 1; + private static final String PREFS_HISTORY = "history"; + private static final String PREFS_NAME = "SpellIt"; + private static final String PREFS_NATO = "nato"; + + private String[] mAlphabet; + private int mCurrentChar = -1; + private String mEntry; + private final List mHistory = new ArrayList(MAX_HISTORY_SIZE); + private boolean mNato; + + /** + * Adds to the history. + * + * @param entry The entry to add. + */ + private void addHistory(String entry) + { + if (!mHistory.contains(entry)) + { + if (mHistory.size() >= MAX_HISTORY_SIZE) + { + mHistory.remove(0); + } + + mHistory.add(entry); + + savePrefs(); + } + } + + /** + * Returns the specified phonetic alphabet value. + * + * @param index The desired alphabet index. + * @return The specified alphabet value. + */ + private String getAlphabet(int index) + { + return mAlphabet[index]; + } + + /** + * Returns the current character count. + * + * @return The current character count. + */ + private int getCurrentChar() + { + return mCurrentChar; + } + + /** + * Gets the current entry. + * + * @return The new entry. + */ + private String getEntry() + { + return mEntry; + } + + /** + * Returns the current version number. + * + * @return The current version number or empty. + */ + private String getVersionNumber() + { + try + { + return getPackageManager().getPackageInfo(getPackageName(), 0).versionName; + } + catch (final NameNotFoundException e) + { + return ""; + } + } + + /** + * Initializes the various controls. + */ + private void init() + { + final AutoCompleteTextView entryFld = (AutoCompleteTextView) findViewById(R.id.main_entry_fld); + final Button spellBtn = (Button) findViewById(R.id.main_spell_btn); + final TextView resultFld = (TextView) findViewById(R.id.main_result_fld); + final TextView tapLbl = (TextView) findViewById(R.id.main_tap_lbl); + + final SharedPreferences settings = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + + setHistory(settings.getString(PREFS_HISTORY, "")); + setNato(settings.getBoolean(PREFS_NATO, false)); + setAutoComplete(entryFld); + setAlphabet(isNato()); + + final ClipboardManager clip = (ClipboardManager) getSystemService(android.content.Context.CLIPBOARD_SERVICE); + if (clip.hasText()) + { + entryFld.setText(clip.getText()); + } + + entryFld.setOnClickListener(new Button.OnClickListener() + { + public void onClick(View view) + { + spellBtn.performClick(); + } + }); + + spellBtn.setOnClickListener(new Button.OnClickListener() + { + public void onClick(View view) + { + final String newEntry = entryFld.getText().toString(); + + if (!TextUtils.isEmpty(newEntry)) + { + tapLbl.setText(R.string.main_tap_lbl_txt); + + if (!newEntry.equals(getEntry())) + { + setEntry(newEntry); + setCurrentChar(0); + addHistory(getEntry()); + setAutoComplete(entryFld); + } + showNextChar(resultFld, tapLbl); + } + else + { + Toast.makeText(SpellIt.this, R.string.main_entry_err_txt, Toast.LENGTH_SHORT).show(); + } + } + }); + + resultFld.setOnClickListener(new Button.OnClickListener() + { + public void onClick(View view) + { + if (getCurrentChar() >= 0) + { + showNextChar(resultFld, tapLbl); + } + } + }); + + tapLbl.setOnClickListener(new Button.OnClickListener() + { + public void onClick(View view) + { + if (getCurrentChar() >= 0) + { + showNextChar(resultFld, tapLbl); + } + } + }); + } + + /** + * Returns the NATO flag. + * + * @return The NATO flag. + */ + private boolean isNato() + { + return mNato; + } + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + init(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) + { + menu.add(0, MENU_ABOUT, 0, R.string.about_menu_txt).setIcon(android.R.drawable.ic_menu_info_details); + menu.add(0, MENU_NATO, 0, R.string.nato_menu_txt); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + if (item.getItemId() == MENU_ABOUT) + { + final LayoutInflater factory = LayoutInflater.from(this); + final View aboutView = factory.inflate(R.layout.about, null); + + new AlertDialog.Builder(this).setView(aboutView).setIcon(android.R.drawable.ic_dialog_info).setTitle( + getString(R.string.app_name) + ' ' + getVersionNumber()).setPositiveButton(R.string.alert_dialog_ok, + new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int whichButton) + { + // do nothing + } + }).show(); + + return true; + } + else if (item.getItemId() == MENU_NATO) + { + setAlphabet(toggleNato()); + savePrefs(); + + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) + { + super.onPrepareOptionsMenu(menu); + + if (isNato()) + { + menu.findItem(MENU_NATO).setIcon(android.R.drawable.presence_online); + } + else + { + menu.findItem(MENU_NATO).setIcon(android.R.drawable.presence_offline); + } + + return true; + } + + /** + * Saves the preferences. + */ + private void savePrefs() + { + final SharedPreferences settings = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); + final SharedPreferences.Editor editor = settings.edit(); + editor.putString(PREFS_HISTORY, TextUtils.join(",", mHistory)); + editor.putBoolean(PREFS_NATO, isNato()); + editor.commit(); + } + + /** + * Set the alphabet. + * + * @param isNato The NATO flag. + */ + private void setAlphabet(Boolean isNato) + { + if (isNato) + { + mAlphabet = getResources().getStringArray(R.array.nato_alphabet); + } + else + { + mAlphabet = getResources().getStringArray(R.array.alphabet); + } + } + + /** + * Sets the auto-complete values of the specified field. + * + * @param field The field to the auto-complete for. + */ + private void setAutoComplete(AutoCompleteTextView field) + { + final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, mHistory); + field.setAdapter(adapter); + } + + /** + * Sets the current character count. + * + * @param count The current character count to set. + */ + private void setCurrentChar(int count) + { + mCurrentChar = count; + } + + /** + * Sets the current entry. + * + * @param entry The entry to set. + */ + private void setEntry(String entry) + { + mEntry = entry; + } + + /** + * Sets the history. + * + * @param history The comma-delimited history string. + */ + private void setHistory(String history) + { + final String[] entries = TextUtils.split(history, ","); + for (final String entry : entries) + { + mHistory.add(entry); + } + } + + /** + * Sets the NATO flag. + * + * @param nato The new NATO flag. + */ + private void setNato(boolean isNato) + { + mNato = isNato; + } + + private void showNextChar(TextView view, TextView label) + { + if (getCurrentChar() < getEntry().length()) + { + final char c = getEntry().charAt(getCurrentChar()); + + if ((c < 123) && (c > 96)) + { + int offset = 97; + + if ((c < 91) && (c > 64)) + { + offset = 65; + } + + view.setText(String.valueOf(c).toUpperCase() + ' ' + getString(R.string.as_in_txt) + ' ' + getAlphabet(c - offset)); + } + else if ((c < 58) && (c > 47)) + { + view.setText(getAlphabet(c - 22)); + } + else if (c == ' ') + { + view.setText(getString(R.string.space_txt)); + } + else + { + view.setText(String.valueOf(c)); + } + + setCurrentChar(getCurrentChar() + 1); + } + else + { + view.setText(getString(R.string.done_txt)); + label.setText(getString(R.string.main_tap_lbl_repeat_txt)); + setCurrentChar(0); + } + } + + /** + * Toggles the NATO flag. + * + * @return The NATO flag value. + */ + private boolean toggleNato() + { + mNato ^= true; + + return mNato; + } + +} \ No newline at end of file