├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── MuklukMudClient
├── libs
│ ├── jackson-core-asl-1.9.0.jar
│ ├── GoogleAdMobAdsSdk-4.1.1.jar
│ └── jackson-mapper-asl-1.9.0.jar
├── src
│ └── main
│ │ ├── ic_launcher_boot-web.png
│ │ ├── ic_notification_boot-web.png
│ │ ├── res
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher_boot.png
│ │ │ └── ic_notification_boot.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher_boot.png
│ │ │ └── ic_notification_boot.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher_boot.png
│ │ │ └── ic_notification_boot.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher_boot.png
│ │ │ └── ic_notification_boot.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher_boot.png
│ │ │ └── ic_notification_boot.png
│ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── attrs.xml
│ │ │ └── strings.xml
│ │ ├── values-en-rAU
│ │ │ └── strings.xml
│ │ ├── values-en-rCA
│ │ │ └── strings.xml
│ │ ├── values-en-rGB
│ │ │ └── strings.xml
│ │ ├── drawable
│ │ │ └── entrystyle.xml
│ │ ├── menu
│ │ │ ├── world_list_context_menu.xml
│ │ │ ├── world_list_menu.xml
│ │ │ └── world_connection_menu.xml
│ │ ├── layout
│ │ │ ├── checkbox_dialog.xml
│ │ │ ├── text_dialog.xml
│ │ │ ├── world_list_row.xml
│ │ │ ├── world_list.xml
│ │ │ ├── text_size_preference.xml
│ │ │ ├── world_connection.xml
│ │ │ ├── color_preference.xml
│ │ │ ├── about.xml
│ │ │ └── add_edit_world.xml
│ │ └── xml
│ │ │ └── global_settings.xml
│ │ ├── java
│ │ └── com
│ │ │ └── crap
│ │ │ └── mukluk
│ │ │ ├── StyleInfo.java
│ │ │ ├── GlobalSettingsActivity.java
│ │ │ ├── AboutActivity.java
│ │ │ ├── BlockingQueue.java
│ │ │ ├── FixedSizeList.java
│ │ │ ├── SerializableWorld.java
│ │ │ ├── IndexedColors.java
│ │ │ ├── WorldMessage.java
│ │ │ ├── Utility.java
│ │ │ ├── LineStyleInfo.java
│ │ │ ├── WorldListAdapter.java
│ │ │ ├── EchoColorPreference.java
│ │ │ ├── BackgroundColorPreference.java
│ │ │ ├── ForegroundColorPreference.java
│ │ │ ├── TextSizePreference.java
│ │ │ ├── World.java
│ │ │ ├── WorldDbAdapter.java
│ │ │ ├── ConsoleTextHistory.java
│ │ │ ├── TcpConnection.java
│ │ │ ├── WorldConnectionService.java
│ │ │ ├── AddEditWorldActivity.java
│ │ │ ├── AnsiUtility.java
│ │ │ └── WorldListActivity.java
│ │ └── AndroidManifest.xml
└── build.gradle
├── README.md
├── LICENSE.md
├── gradlew.bat
├── .gitattributes
├── gradlew
└── .gitignore
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':MuklukMudClient'
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/MuklukMudClient/libs/jackson-core-asl-1.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/libs/jackson-core-asl-1.9.0.jar
--------------------------------------------------------------------------------
/MuklukMudClient/libs/GoogleAdMobAdsSdk-4.1.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/libs/GoogleAdMobAdsSdk-4.1.1.jar
--------------------------------------------------------------------------------
/MuklukMudClient/libs/jackson-mapper-asl-1.9.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/libs/jackson-mapper-asl-1.9.0.jar
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/ic_launcher_boot-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/ic_launcher_boot-web.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/ic_notification_boot-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/ic_notification_boot-web.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-hdpi/ic_launcher_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-hdpi/ic_launcher_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-mdpi/ic_launcher_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-mdpi/ic_launcher_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-xhdpi/ic_launcher_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-xhdpi/ic_launcher_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-xxhdpi/ic_launcher_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-xxhdpi/ic_launcher_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-xxxhdpi/ic_launcher_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-xxxhdpi/ic_launcher_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-hdpi/ic_notification_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-hdpi/ic_notification_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-mdpi/ic_notification_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-mdpi/ic_notification_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-xhdpi/ic_notification_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-xhdpi/ic_notification_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-xxhdpi/ic_notification_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-xxhdpi/ic_notification_boot.png
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/mipmap-xxxhdpi/ic_notification_boot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kyrie1965/Mukluk/master/MuklukMudClient/src/main/res/mipmap-xxxhdpi/ic_notification_boot.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 20 20:30:11 EDT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #A4C639
4 | #000000
5 | #BEBEBE
6 | #181818
7 | #FFFFFF
8 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/StyleInfo.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.text.style.CharacterStyle;
4 |
5 | public class StyleInfo
6 | {
7 | CharacterStyle style;
8 | int start;
9 | int end;
10 |
11 | public StyleInfo(CharacterStyle style, int start)
12 | {
13 | this.style = style;
14 | this.start = start;
15 | this.end = -1;
16 | }
17 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Mukluk MUD Client is an Android M* (MUDs, MUSHs, MOOs, etc.) client that was originally added to the Google Play Store in 2010. It featured full ANSI support and the ability to connect to multiple worlds simultaneously.
2 |
3 | Mukluk no longer works on more recent versions of Android due to changes in the operating system's behavior and security. The source code is provided for anybody to do whatever they like with it. Enjoy!
4 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/values-en-rAU/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Background Colour
5 | Text Colour
6 | Command Colour
7 |
8 |
9 | ANSI Colours Enabled
10 |
11 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/values-en-rCA/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Background Colour
5 | Text Colour
6 | Command Colour
7 |
8 |
9 | ANSI Colours Enabled
10 |
11 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/values-en-rGB/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Background Colour
5 | Text Colour
6 | Command Colour
7 |
8 |
9 | ANSI Colours Enabled
10 |
11 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/drawable/entrystyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
14 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/GlobalSettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.os.Bundle;
4 | import android.preference.PreferenceActivity;
5 |
6 | public class GlobalSettingsActivity extends PreferenceActivity
7 | {
8 | @Override
9 | public void onCreate(Bundle savedInstanceState)
10 | {
11 | super.onCreate(savedInstanceState);
12 | addPreferencesFromResource(R.xml.global_settings);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/menu/world_list_context_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/checkbox_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
20 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/text_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
19 |
25 |
26 |
--------------------------------------------------------------------------------
/MuklukMudClient/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 16
5 | buildToolsVersion "21.1.2"
6 |
7 | defaultConfig {
8 | applicationId "com.crap.mukluk"
9 | minSdkVersion 11
10 | targetSdkVersion 16
11 | versionCode 205
12 | versionName "2.05"
13 | }
14 |
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
19 | }
20 | }
21 |
22 | packagingOptions {
23 | exclude 'META-INF/ASL2.0'
24 | exclude 'META-INF/LICENSE'
25 | exclude 'META-INF/MANIFEST.MF'
26 | exclude 'META-INF/NOTICE'
27 | }
28 | }
29 |
30 | dependencies {
31 | compile files('libs/jackson-core-asl-1.9.0.jar')
32 | compile files('libs/jackson-mapper-asl-1.9.0.jar')
33 | }
34 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/AboutActivity.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.app.Activity;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.content.pm.PackageManager.NameNotFoundException;
7 | import android.os.Bundle;
8 | import android.widget.TextView;
9 |
10 | public class AboutActivity extends Activity
11 | {
12 | @Override
13 | public void onCreate(Bundle savedInstanceState)
14 | {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.about);
17 |
18 | TextView version = (TextView) findViewById(R.id.text_version);
19 | PackageManager pm = getPackageManager();
20 | PackageInfo pInfo;
21 |
22 | try
23 | {
24 | pInfo = pm.getPackageInfo("com.crap.mukluk", 0);
25 | version.setText(pInfo.versionName);
26 | }
27 | catch (NameNotFoundException ex)
28 | {
29 | version.setText("Unknown Version");
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/menu/world_list_menu.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/BlockingQueue.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.util.LinkedList;
4 |
5 | public class BlockingQueue
6 | {
7 | private LinkedList list;
8 |
9 | public BlockingQueue()
10 | {
11 | list = new LinkedList();
12 | }
13 |
14 | public synchronized void addMessage(T msg)
15 | {
16 | list.addLast(msg);
17 |
18 | notifyAll();
19 | }
20 |
21 | // Gets a message from the queue. If none are available, blocks until some become available.
22 | // Returns null if thread interrupted
23 | // Returns null if queue will no longer be delivering messages
24 | public synchronized T getMessage()
25 | {
26 | while (list.size() == 0 /*&& !shutDownFlag*/)
27 | {
28 | try
29 | {
30 | wait();
31 | }
32 | catch (InterruptedException e)
33 | {
34 | return null;
35 | }
36 | }
37 |
38 | return list.removeFirst();
39 | }
40 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Mukluk is released under the MIT license.
2 |
3 | Copyright (c) 2010-2022
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/FixedSizeList.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.util.LinkedList;
4 |
5 | // A queue where items are removed if the list exceeds a certain size
6 | @SuppressWarnings("serial")
7 | public class FixedSizeList extends LinkedList
8 | {
9 | int _maximumSize;
10 |
11 | public FixedSizeList(int maximumSize)
12 | {
13 | super();
14 |
15 | _maximumSize = maximumSize;
16 | }
17 |
18 | public boolean add(E item)
19 | {
20 | boolean addResult = super.add(item);
21 |
22 | if (this.size() > _maximumSize)
23 | this.removeFirst();
24 |
25 | return addResult;
26 | }
27 |
28 | public void addFirst(E item)
29 | {
30 | super.addFirst(item);
31 |
32 | if (this.size() > _maximumSize)
33 | this.removeLast();
34 | }
35 |
36 | public void setMaximumSize(int newMaximumSize)
37 | {
38 | int currentSize = this.size();
39 |
40 | if (currentSize > newMaximumSize)
41 | this.subList(0, currentSize - newMaximumSize).clear();
42 |
43 | _maximumSize = newMaximumSize;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/menu/world_connection_menu.xml:
--------------------------------------------------------------------------------
1 |
33 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/world_list_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
27 |
28 |
37 |
38 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/SerializableWorld.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.io.Serializable;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | // Weird errors occur when a class is both parcelable and serializable, so use this to export and import World class
8 | public class SerializableWorld implements Serializable
9 | {
10 | private static final long serialVersionUID = 358488681588640820L;
11 | public String name;
12 | public String host;
13 | public int port = 0;
14 | public boolean loggingEnabled = false;
15 | public boolean ansiColorEnabled = true;
16 | public String encodingName;
17 | public List postLoginCommands = new ArrayList();
18 |
19 | public SerializableWorld(World world)
20 | {
21 | this.name = world.name;
22 | this.host = world.host;
23 | this.port = world.port;
24 | this.loggingEnabled = world.loggingEnabled;
25 | this.ansiColorEnabled = world.ansiColorEnabled;
26 | this.encodingName = world.encoding.name();
27 | postLoginCommands.addAll(world.postLoginCommands);
28 | }
29 |
30 | public World getAsWorld()
31 | {
32 | World world = new World();
33 | world.name = name;
34 | world.host = host;
35 | world.port = port;
36 | world.loggingEnabled = loggingEnabled;
37 | world.ansiColorEnabled = ansiColorEnabled;
38 | world.setCharset(encodingName);
39 | world.postLoginCommands.addAll(postLoginCommands);
40 |
41 | return world;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/world_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
18 |
29 |
34 |
43 |
44 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/IndexedColors.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.graphics.Color;
4 |
5 | public class IndexedColors
6 | {
7 | public int[] colorTable = new int[256];
8 |
9 | public IndexedColors()
10 | {
11 | // first 16 colors are light and dark versions of the basic 8 VGA colors
12 | colorTable[0] = Color.parseColor("#000000");
13 | colorTable[1] = Color.parseColor("#cd0000");
14 | colorTable[2] = Color.parseColor("#00cd00");
15 | colorTable[3] = Color.parseColor("#cdcd00");
16 | colorTable[4] = Color.parseColor("#0000ee");
17 | colorTable[5] = Color.parseColor("#cd00cd");
18 | colorTable[6] = Color.parseColor("#00cdcd");
19 | colorTable[7] = Color.parseColor("#e5e5e5");
20 | colorTable[8] = Color.parseColor("#7f7f7f");
21 | colorTable[9] = Color.parseColor("#ff0000");
22 | colorTable[10] = Color.parseColor("#00ff00");
23 | colorTable[11] = Color.parseColor("#ffff00");
24 | colorTable[12] = Color.parseColor("#5c5cff");
25 | colorTable[13] = Color.parseColor("#ff00ff");
26 | colorTable[14] = Color.parseColor("#00ffff");
27 | colorTable[15] = Color.parseColor("#ffffff");
28 |
29 | // middle 216
30 | for (int red = 0; red <= 5; red++)
31 | {
32 | for (int green = 0; green <= 5; green++)
33 | {
34 | for (int blue = 0; blue <= 5; blue++)
35 | {
36 | int index = 16 + (red * 36) + (green * 6) + blue;
37 |
38 | colorTable[index] = Color.rgb((red * 40) + 55, (green * 40) + 55, (blue * 40) + 55);
39 | }
40 | }
41 | }
42 |
43 | // last 24 are a greyscale ramp
44 | for (int i = 0; i <= 23; i++)
45 | {
46 | int whiteness = (i * 10) + 8;
47 | colorTable[i + 232] = Color.rgb(whiteness, whiteness, whiteness);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/WorldMessage.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.content.ContentValues;
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 |
7 | // Represents messages from world -> activity or activity -> world
8 | public class WorldMessage implements Parcelable
9 | {
10 | public static final int MESSAGE_TYPE_ERROR = -1;
11 | public static final int MESSAGE_TYPE_STATUS_CHANGE = 0;
12 | public static final int MESSAGE_TYPE_TEXT = 1;
13 |
14 | public int type;
15 | public int currentStatus;
16 | public CharSequence text;
17 |
18 | public WorldMessage(int type, int currentStatus, CharSequence text)
19 | {
20 | this.type = type;
21 | this.currentStatus = currentStatus;
22 | this.text = text;
23 | }
24 |
25 | public WorldMessage(Parcel in)
26 | {
27 | type = in.readInt();
28 | currentStatus = in.readInt();
29 | text = in.readString();
30 | }
31 |
32 | public ContentValues getContentValues()
33 | {
34 | ContentValues vals = new ContentValues(3);
35 |
36 | vals.put("type", type);
37 | vals.put("currentStatus", currentStatus);
38 | vals.put("text", (String) text);
39 |
40 | return vals;
41 | }
42 |
43 | @Override
44 | public int describeContents()
45 | {
46 | return 0;
47 | }
48 |
49 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator()
50 | {
51 | public WorldMessage createFromParcel(Parcel in)
52 | {
53 | return new WorldMessage(in);
54 | }
55 |
56 | public WorldMessage[] newArray(int size)
57 | {
58 | return new WorldMessage[size];
59 | }
60 | };
61 |
62 | @Override
63 | public void writeToParcel(Parcel dest, int flags)
64 | {
65 | dest.writeInt(type);
66 | dest.writeInt(currentStatus);
67 | dest.writeString((String) text);
68 | }
69 | }
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/Utility.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.nio.charset.Charset;
4 | import java.util.LinkedList;
5 | import java.util.regex.Matcher;
6 | import java.util.regex.Pattern;
7 |
8 | import android.content.Context;
9 | import android.net.ConnectivityManager;
10 | import android.net.NetworkInfo;
11 |
12 | public abstract class Utility
13 | {
14 | private static final Pattern NON_ALPHA_PATTERN = Pattern.compile("[^A-Za-z\\d]");
15 | private static String[] _supportedCharsetNames = null;
16 |
17 | // Get an array with names of the supported charsets. Cache this so it only
18 | // has to be got once
19 | public static String[] getSupportedCharsetNames()
20 | {
21 | if (_supportedCharsetNames == null)
22 | {
23 | LinkedList availableCharsets = new LinkedList();
24 |
25 | for (Charset enc : Charset.availableCharsets().values())
26 | {
27 | availableCharsets.add(enc.name());
28 | }
29 |
30 | _supportedCharsetNames = new String[availableCharsets.size()];
31 |
32 | availableCharsets.toArray(_supportedCharsetNames);
33 | }
34 |
35 | return _supportedCharsetNames;
36 | }
37 |
38 | public static boolean isInternetConnectionAvailable(Context context)
39 | {
40 | ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
41 | NetworkInfo wifi = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
42 | NetworkInfo mobile = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
43 |
44 | if (wifi.isAvailable() || mobile.isAvailable())
45 | return true;
46 | else
47 | return false;
48 | }
49 |
50 | public static String stripNonAlphanumericCharacters(String originalString)
51 | {
52 | Matcher m = NON_ALPHA_PATTERN.matcher(originalString);
53 |
54 | return m.replaceAll("");
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/text_size_preference.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
21 |
28 |
31 |
38 |
46 |
47 |
50 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/LineStyleInfo.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.io.Serializable;
4 | import java.util.ArrayList;
5 | import java.util.Collection;
6 |
7 | import org.json.JSONArray;
8 | import org.json.JSONException;
9 | import org.json.JSONObject;
10 |
11 | import android.util.Log;
12 |
13 | public class LineStyleInfo implements Serializable
14 | {
15 | private static final long serialVersionUID = 3731247399806081144L;
16 |
17 | public int lineNumber;
18 | public int start;
19 | public int end;
20 | public ArrayList ansiCode;
21 |
22 | public LineStyleInfo()
23 | {
24 | this.lineNumber = -1;
25 | this.start = -1;
26 | this.end = -1;
27 | this.ansiCode = new ArrayList();
28 | }
29 |
30 | public LineStyleInfo(JSONObject jobj)
31 | {
32 | try
33 | {
34 | this.lineNumber = jobj.getInt("lineNumber");
35 | this.start = jobj.getInt("start");
36 | this.end = jobj.getInt("end");
37 |
38 | JSONArray jarr = jobj.optJSONArray("ansiCode");
39 | int len = jarr.length();
40 |
41 | this.ansiCode = new ArrayList();
42 |
43 | for (int i = 0; i < len; i++)
44 | {
45 | ansiCode.add(jarr.getInt(i));
46 | }
47 | }
48 | catch (JSONException ex)
49 | {
50 | Log.e("LineStyleInfo", ex.toString());
51 | }
52 | }
53 |
54 | public JSONObject asJson()
55 | {
56 | JSONObject jo = new JSONObject();
57 |
58 | try
59 | {
60 | jo.put("lineNumber", lineNumber);
61 | jo.put("start", start);
62 | jo.put("end", end);
63 | jo.put("ansiCode", new JSONArray(ansiCode));
64 | }
65 | catch (JSONException ex)
66 | {
67 | Log.e("LineStyleInfo", ex.toString());
68 | }
69 |
70 | return jo;
71 | }
72 |
73 | public static JSONArray GetJsonArray(Collection list)
74 | {
75 | JSONArray jarr = new JSONArray();
76 |
77 | for (LineStyleInfo lsi : list)
78 | jarr.put(lsi.asJson());
79 |
80 | return jarr;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/world_connection.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
17 |
26 |
42 |
50 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/color_preference.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
21 |
28 |
31 |
38 |
46 |
47 |
50 |
57 |
65 |
66 |
67 |
74 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/WorldListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.BaseAdapter;
9 | import android.widget.RelativeLayout;
10 | import android.widget.TextView;
11 |
12 | // adapter that converts World[] to a view
13 | public class WorldListAdapter extends BaseAdapter
14 | {
15 | private Context context;
16 | private World[] worlds;
17 | private LayoutInflater inflater;
18 |
19 | public WorldListAdapter(Context context, World[] worlds)
20 | {
21 | this.context = context;
22 | this.worlds = worlds;
23 | inflater = LayoutInflater.from(context);
24 | }
25 |
26 | public int getConnectedWorlds()
27 | {
28 | int numConnected = 0;
29 |
30 | for (World w : worlds)
31 | {
32 | if (WorldConnectionService.getWorldConnectionStatus(w.dbID) == WorldConnectionService.STATUS_CONNECTED)
33 | {
34 | numConnected++;
35 | }
36 | }
37 |
38 | return numConnected;
39 | }
40 |
41 | @Override
42 | public int getCount()
43 | {
44 | return worlds.length;
45 | }
46 |
47 | @Override
48 | public Object getItem(int position)
49 | {
50 | return worlds[position];
51 | }
52 |
53 | @Override
54 | public long getItemId(int position)
55 | {
56 | return worlds[position].dbID;
57 | }
58 |
59 | @Override
60 | public View getView(int position, View convertView, ViewGroup parent)
61 | {
62 | World world = worlds[position];
63 | RelativeLayout row;
64 |
65 | if (convertView == null || !(convertView instanceof RelativeLayout))
66 | row = (RelativeLayout) inflater.inflate(R.layout.world_list_row, null);
67 | else
68 | row = (RelativeLayout) convertView;
69 |
70 | TextView txtName = (TextView) row.findViewById(R.id.row_world_name);
71 | txtName.setText(world.name.trim().length() == 0 ? "[Unnamed World]" : world.name);
72 |
73 | TextView txtHost = (TextView) row.findViewById(R.id.row_world_host);
74 | txtHost.setText(world.host.trim().length() == 0 ? "[world address not set]" : world.host + " : " + world.port);
75 |
76 | TextView txtStatus = (TextView) row.findViewById(R.id.row_world_status);
77 |
78 | txtStatus.setText(WorldConnectionService.getWorldConnectionStatusDescription(context, WorldConnectionService.getWorldConnectionStatus(world.dbID)));
79 |
80 | switch (WorldConnectionService.getWorldConnectionStatus(world.dbID))
81 | {
82 | case (WorldConnectionService.STATUS_NOT_CONNECTED):
83 | txtStatus.setTextColor(Color.RED);
84 | break;
85 | case (WorldConnectionService.STATUS_CONNECTING):
86 | txtStatus.setTextColor(Color.GREEN);
87 | break;
88 | case (WorldConnectionService.STATUS_CONNECTED):
89 | txtStatus.setTextColor(Color.GREEN);
90 | break;
91 | case (WorldConnectionService.STATUS_DISCONNECTING):
92 | txtStatus.setTextColor(Color.RED);
93 | break;
94 | }
95 |
96 | return row;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/about.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
19 |
27 |
37 |
45 |
55 |
65 |
73 |
83 |
91 |
101 |
102 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/EchoColorPreference.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.graphics.Color;
6 | import android.preference.Preference;
7 | import android.preference.PreferenceManager;
8 | import android.util.AttributeSet;
9 | import android.util.TypedValue;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.SeekBar;
14 | import android.widget.TextView;
15 | import android.widget.SeekBar.OnSeekBarChangeListener;
16 |
17 | public class EchoColorPreference extends Preference
18 | {
19 | public static final int defaultEchoColor = Color.rgb(255, 255, 0);
20 | private String backgroundColorKey;
21 | private String textSizeKey;
22 | private TextView txtSample;
23 | private SeekBar redBar;
24 | private SeekBar greenBar;
25 | private SeekBar blueBar;
26 |
27 | private final OnSeekBarChangeListener seekBarListener = new OnSeekBarChangeListener()
28 | {
29 | @Override
30 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
31 | {
32 | if (fromUser)
33 | {
34 | int c = Color.rgb(redBar.getProgress(), greenBar.getProgress(), blueBar.getProgress());
35 | txtSample.setTextColor(c);
36 | updatePreference(c);
37 | }
38 | }
39 |
40 | @Override
41 | public void onStartTrackingTouch(SeekBar seekBar) {}
42 |
43 | @Override
44 | public void onStopTrackingTouch(SeekBar seekBar) {}
45 | };
46 |
47 | public EchoColorPreference(Context context)
48 | {
49 | super(context);
50 | }
51 |
52 | public EchoColorPreference(Context context, AttributeSet attrs)
53 | {
54 | super(context, attrs);
55 | init(attrs);
56 | }
57 |
58 | public EchoColorPreference(Context context, AttributeSet attrs, int defStyle)
59 | {
60 | super(context, attrs, defStyle);
61 | init(attrs);
62 | }
63 |
64 | private void init(AttributeSet attrs)
65 | {
66 | String namespace = "http://schemas.android.com/apk/res/com.crap.mukluk";
67 | backgroundColorKey = attrs.getAttributeValue(namespace, "backgroundColorKey");
68 | textSizeKey = attrs.getAttributeValue(namespace, "textSizeKey");
69 | }
70 |
71 | @Override
72 | public View onCreateView(ViewGroup parent)
73 | {
74 | LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
75 | View view = inflater.inflate(R.layout.color_preference, null);
76 |
77 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
78 | int colorVal = prefs.getInt(getKey(), defaultEchoColor);
79 |
80 | txtSample = (TextView) view.findViewById(R.id.sample_text);
81 | txtSample.setTextColor(colorVal);
82 | txtSample.setBackgroundColor(prefs.getInt(backgroundColorKey, BackgroundColorPreference.defaultBackgroundColor));
83 | txtSample.setTextSize(TypedValue.COMPLEX_UNIT_DIP, prefs.getInt(textSizeKey, TextSizePreference.defaultTextSize));
84 |
85 | redBar = (SeekBar) view.findViewById(R.id.red_bar);
86 | redBar.setOnSeekBarChangeListener(seekBarListener);
87 | redBar.setProgress(Color.red(colorVal));
88 |
89 | greenBar = (SeekBar) view.findViewById(R.id.green_bar);
90 | greenBar.setOnSeekBarChangeListener(seekBarListener);
91 | greenBar.setProgress(Color.green(colorVal));
92 |
93 | blueBar = (SeekBar) view.findViewById(R.id.blue_bar);
94 | blueBar.setOnSeekBarChangeListener(seekBarListener);
95 | blueBar.setProgress(Color.blue(colorVal));
96 |
97 | return view;
98 | }
99 |
100 | private void updatePreference(int newValue)
101 | {
102 | SharedPreferences.Editor editor = getEditor();
103 | editor.putInt(getKey(), newValue);
104 | editor.commit();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/BackgroundColorPreference.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.preference.Preference;
4 | import android.preference.PreferenceManager;
5 | import android.util.AttributeSet;
6 | import android.util.TypedValue;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.SeekBar;
11 | import android.widget.TextView;
12 | import android.widget.SeekBar.OnSeekBarChangeListener;
13 | import android.content.Context;
14 | import android.content.SharedPreferences;
15 | import android.graphics.Color;
16 |
17 | public class BackgroundColorPreference extends Preference
18 | {
19 | public static final int defaultBackgroundColor = Color.rgb(0, 0, 0);
20 | private String foregroundColorKey;
21 | private String textSizeKey;
22 | private TextView txtSample;
23 | private SeekBar redBar;
24 | private SeekBar greenBar;
25 | private SeekBar blueBar;
26 |
27 | private final OnSeekBarChangeListener seekBarListener = new OnSeekBarChangeListener()
28 | {
29 | @Override
30 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
31 | {
32 | if (fromUser)
33 | {
34 | int c = Color.rgb(redBar.getProgress(), greenBar.getProgress(), blueBar.getProgress());
35 | txtSample.setBackgroundColor(c);
36 | updatePreference(c);
37 | }
38 | }
39 |
40 | @Override
41 | public void onStartTrackingTouch(SeekBar seekBar) {}
42 |
43 | @Override
44 | public void onStopTrackingTouch(SeekBar seekBar) {}
45 | };
46 |
47 | public BackgroundColorPreference(Context context)
48 | {
49 | super(context);
50 | }
51 |
52 | public BackgroundColorPreference(Context context, AttributeSet attrs)
53 | {
54 | super(context, attrs);
55 | init(attrs);
56 | }
57 |
58 | public BackgroundColorPreference(Context context, AttributeSet attrs, int defStyle)
59 | {
60 | super(context, attrs, defStyle);
61 | init(attrs);
62 | }
63 |
64 | private void init(AttributeSet attrs)
65 | {
66 | String namespace = "http://schemas.android.com/apk/res/com.crap.mukluk";
67 | foregroundColorKey = attrs.getAttributeValue(namespace, "foregroundColorKey");
68 | textSizeKey = attrs.getAttributeValue(namespace, "textSizeKey");
69 | }
70 |
71 | @Override
72 | public View onCreateView(ViewGroup parent)
73 | {
74 | LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
75 | View view = inflater.inflate(R.layout.color_preference, null);
76 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
77 | int colorVal = prefs.getInt(getKey(), defaultBackgroundColor);
78 |
79 | txtSample = (TextView) view.findViewById(R.id.sample_text);
80 | txtSample.setBackgroundColor(colorVal);
81 | txtSample.setTextSize(TypedValue.COMPLEX_UNIT_DIP, prefs.getInt(textSizeKey, TextSizePreference.defaultTextSize));
82 | txtSample.setTextColor(prefs.getInt(foregroundColorKey, ForegroundColorPreference.defaultForegroundColor));
83 |
84 | redBar = (SeekBar) view.findViewById(R.id.red_bar);
85 | redBar.setOnSeekBarChangeListener(seekBarListener);
86 | redBar.setProgress(Color.red(colorVal));
87 |
88 | greenBar = (SeekBar) view.findViewById(R.id.green_bar);
89 | greenBar.setOnSeekBarChangeListener(seekBarListener);
90 | greenBar.setProgress(Color.green(colorVal));
91 |
92 | blueBar = (SeekBar) view.findViewById(R.id.blue_bar);
93 | blueBar.setOnSeekBarChangeListener(seekBarListener);
94 | blueBar.setProgress(Color.blue(colorVal));
95 |
96 | return view;
97 | }
98 |
99 | private void updatePreference(int newValue)
100 | {
101 | SharedPreferences.Editor editor = getEditor();
102 | editor.putInt(getKey(), newValue);
103 | editor.commit();
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/ForegroundColorPreference.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.preference.Preference;
4 | import android.preference.PreferenceManager;
5 | import android.util.AttributeSet;
6 | import android.util.TypedValue;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.SeekBar;
11 | import android.widget.TextView;
12 | import android.widget.SeekBar.OnSeekBarChangeListener;
13 | import android.content.Context;
14 | import android.content.SharedPreferences;
15 | import android.graphics.Color;
16 |
17 | public class ForegroundColorPreference extends Preference
18 | {
19 | public static final int defaultForegroundColor = Color.rgb(255, 255, 255);
20 | private String backgroundColorKey;
21 | private String textSizeKey;
22 | private TextView txtSample;
23 | private SeekBar redBar;
24 | private SeekBar greenBar;
25 | private SeekBar blueBar;
26 |
27 | private final OnSeekBarChangeListener seekBarListener = new OnSeekBarChangeListener()
28 | {
29 | @Override
30 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
31 | {
32 | if (fromUser)
33 | {
34 | int c = Color.rgb(redBar.getProgress(), greenBar.getProgress(), blueBar.getProgress());
35 | txtSample.setTextColor(c);
36 | updatePreference(c);
37 | }
38 | }
39 |
40 | @Override
41 | public void onStartTrackingTouch(SeekBar seekBar) {}
42 |
43 | @Override
44 | public void onStopTrackingTouch(SeekBar seekBar) {}
45 | };
46 |
47 | public ForegroundColorPreference(Context context)
48 | {
49 | super(context);
50 | }
51 |
52 | public ForegroundColorPreference(Context context, AttributeSet attrs)
53 | {
54 | super(context, attrs);
55 | init(attrs);
56 | }
57 |
58 | public ForegroundColorPreference(Context context, AttributeSet attrs, int defStyle)
59 | {
60 | super(context, attrs, defStyle);
61 | init(attrs);
62 | }
63 |
64 | private void init(AttributeSet attrs)
65 | {
66 | String namespace = "http://schemas.android.com/apk/res/com.crap.mukluk";
67 | backgroundColorKey = attrs.getAttributeValue(namespace, "backgroundColorKey");
68 | textSizeKey = attrs.getAttributeValue(namespace, "textSizeKey");
69 | }
70 |
71 | @Override
72 | public View onCreateView(ViewGroup parent)
73 | {
74 | LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
75 | View view = inflater.inflate(R.layout.color_preference, null);
76 |
77 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
78 | int colorVal = prefs.getInt(getKey(), defaultForegroundColor);
79 |
80 | txtSample = (TextView) view.findViewById(R.id.sample_text);
81 | txtSample.setTextColor(colorVal);
82 | txtSample.setBackgroundColor(prefs.getInt(backgroundColorKey, BackgroundColorPreference.defaultBackgroundColor));
83 | txtSample.setTextSize(TypedValue.COMPLEX_UNIT_DIP, prefs.getInt(textSizeKey, TextSizePreference.defaultTextSize));
84 |
85 | redBar = (SeekBar) view.findViewById(R.id.red_bar);
86 | redBar.setOnSeekBarChangeListener(seekBarListener);
87 | redBar.setProgress(Color.red(colorVal));
88 |
89 | greenBar = (SeekBar) view.findViewById(R.id.green_bar);
90 | greenBar.setOnSeekBarChangeListener(seekBarListener);
91 | greenBar.setProgress(Color.green(colorVal));
92 |
93 | blueBar = (SeekBar) view.findViewById(R.id.blue_bar);
94 | blueBar.setOnSeekBarChangeListener(seekBarListener);
95 | blueBar.setProgress(Color.blue(colorVal));
96 |
97 | return view;
98 | }
99 |
100 | private void updatePreference(int newValue)
101 | {
102 | SharedPreferences.Editor editor = getEditor();
103 | editor.putInt(getKey(), newValue);
104 | editor.commit();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/TextSizePreference.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.Preference;
6 | import android.preference.PreferenceManager;
7 | import android.util.AttributeSet;
8 | import android.util.TypedValue;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.view.View.OnClickListener;
13 | import android.widget.Button;
14 | import android.widget.SeekBar;
15 | import android.widget.TextView;
16 | import android.widget.SeekBar.OnSeekBarChangeListener;
17 |
18 | public class TextSizePreference extends Preference
19 | {
20 | public static final int defaultTextSize = 12;
21 | private String foregroundColorKey;
22 | private String backgroundColorKey;
23 | private TextView txtSample;
24 | private SeekBar barText;
25 | private Button btnDefault;
26 |
27 | public TextSizePreference(Context context)
28 | {
29 | super(context);
30 | }
31 |
32 | public TextSizePreference(Context context, AttributeSet attrs)
33 | {
34 | super(context, attrs);
35 | init(attrs);
36 | }
37 |
38 | public TextSizePreference(Context context, AttributeSet attrs, int defStyle)
39 | {
40 | super(context, attrs, defStyle);
41 | init(attrs);
42 | }
43 |
44 | private void init(AttributeSet attrs)
45 | {
46 | String namespace = "http://schemas.android.com/apk/res/com.crap.mukluk";
47 | foregroundColorKey = attrs.getAttributeValue(namespace, "foregroundColorKey");
48 | backgroundColorKey = attrs.getAttributeValue(namespace, "backgroundColorKey");
49 | }
50 |
51 | @Override
52 | public View onCreateView(ViewGroup parent)
53 | {
54 | LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
55 | View view = inflater.inflate(R.layout.text_size_preference, null);
56 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
57 | int textSize = prefs.getInt(getKey(), defaultTextSize);
58 |
59 | txtSample = (TextView) view.findViewById(R.id.sample_text);
60 | txtSample.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize);
61 | txtSample.setBackgroundColor(prefs.getInt(backgroundColorKey, BackgroundColorPreference.defaultBackgroundColor));
62 | txtSample.setTextColor(prefs.getInt(foregroundColorKey, ForegroundColorPreference.defaultForegroundColor));
63 |
64 | barText = (SeekBar) view.findViewById(R.id.text_size_bar);
65 | barText.setProgress(textSize);
66 | barText.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
67 | {
68 | @Override
69 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
70 | {
71 | if (fromUser)
72 | {
73 | int val = barText.getProgress();
74 |
75 | txtSample.setTextSize(TypedValue.COMPLEX_UNIT_DIP, val);
76 | updatePreference(val);
77 | }
78 | }
79 |
80 | @Override
81 | public void onStartTrackingTouch(SeekBar seekBar) {}
82 |
83 | @Override
84 | public void onStopTrackingTouch(SeekBar seekBar) {}
85 | });
86 |
87 | btnDefault = (Button) view.findViewById(R.id.button_default_text_size);
88 | btnDefault.setOnClickListener(new OnClickListener()
89 | {
90 | @Override
91 | public void onClick(View arg0)
92 | {
93 | int val = defaultTextSize;
94 |
95 | barText.setProgress(val);
96 | txtSample.setTextSize(TypedValue.COMPLEX_UNIT_DIP, val);
97 | updatePreference(val);
98 | }
99 | });
100 |
101 | return view;
102 | }
103 |
104 | private void updatePreference(int newValue)
105 | {
106 | SharedPreferences.Editor editor = getEditor();
107 | editor.putInt(getKey(), newValue);
108 | editor.commit();
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/World.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.nio.charset.Charset;
4 | import java.nio.charset.IllegalCharsetNameException;
5 | import java.nio.charset.UnsupportedCharsetException;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | import android.content.ContentValues;
10 | import android.os.Parcel;
11 | import android.os.Parcelable;
12 |
13 | // An individual MUD, MOO, etc. and its settings
14 | public class World implements Parcelable
15 | {
16 | private static final String HOST_FORMAT = "(%1$s:%2$s)";
17 |
18 | public int dbID = -1;
19 | public String name;
20 | public String host;
21 | public int port = 0;
22 | public boolean loggingEnabled = false;
23 | public boolean ansiColorEnabled = false;
24 | public Charset encoding;
25 | public List postLoginCommands = new ArrayList();
26 |
27 | public World() {}
28 |
29 | public World(int id, String name, String host, int port, boolean loggingEnabled, boolean ansiColor,
30 | String charsetName, List postLoginCommands)
31 | {
32 | this.dbID = id;
33 | this.name = name;
34 | this.host = host;
35 | this.port = port;
36 | this.loggingEnabled = loggingEnabled;
37 | this.ansiColorEnabled = ansiColor;
38 | setCharset(charsetName);
39 | this.postLoginCommands.addAll(postLoginCommands);
40 | }
41 |
42 | public World(Parcel in)
43 | {
44 | dbID = in.readInt();
45 | name = in.readString();
46 | host = in.readString();
47 | port = in.readInt();
48 | loggingEnabled = in.readInt() > 0 ? true : false;
49 | ansiColorEnabled = in.readInt() > 0 ? true : false; // originally
50 | // auto-connect
51 | setCharset(in.readString());
52 | in.readStringList(postLoginCommands);
53 | }
54 |
55 | // Get the contentValues for this world. Doesn't include post-login
56 | // commands.
57 | public ContentValues getContentValues()
58 | {
59 | ContentValues vals = new ContentValues(6);
60 |
61 | vals.put("name", name);
62 | vals.put("host", host);
63 | vals.put("port", port);
64 | vals.put("loggingEnabled", loggingEnabled);
65 | vals.put("ansiColorEnabled", ansiColorEnabled);
66 | vals.put("encoding", encoding.name());
67 |
68 | return vals;
69 | }
70 |
71 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator()
72 | {
73 | public World createFromParcel(Parcel in)
74 | {
75 | return new World(in);
76 | }
77 |
78 | public World[] newArray(int size)
79 | {
80 | return new World[size];
81 | }
82 | };
83 |
84 | @Override
85 | public int describeContents()
86 | {
87 | return 0;
88 | }
89 |
90 | public String getCommandHistoryCacheFileName()
91 | {
92 | return "CommandHistory_" + dbID;
93 | }
94 |
95 | public String getConsoleCacheFileName()
96 | {
97 | return "ConsoleHistory_" + dbID;
98 | }
99 |
100 | public String getConsoleStyleCacheJsonFileName()
101 | {
102 | return "ConsoleStyleHistoryJson_" + dbID;
103 | }
104 |
105 | public String getConsoleStyleCacheJacksonJsonFileName()
106 | {
107 | return "ConsoleStyleHistoryJson_v2_" + dbID;
108 | }
109 |
110 | public String getURLCacheFileName()
111 | {
112 | return "URLHistory_" + dbID;
113 | }
114 |
115 | public String getHostAsString()
116 | {
117 | return String.format(HOST_FORMAT, host, port);
118 | }
119 |
120 | @Override
121 | public void writeToParcel(Parcel dest, int flags)
122 | {
123 | dest.writeInt(dbID);
124 | dest.writeString(name);
125 | dest.writeString(host);
126 | dest.writeInt(port);
127 | dest.writeInt(loggingEnabled ? 1 : 0);
128 | dest.writeInt(ansiColorEnabled ? 1 : 0);
129 | dest.writeString(encoding.name());
130 | dest.writeStringList(postLoginCommands);
131 | }
132 |
133 | public void setCharset(String charsetName)
134 | {
135 | if (charsetName == null || charsetName.length() == 0)
136 | {
137 | this.encoding = Charset.forName("UTF-8");
138 | }
139 | else
140 | {
141 | try
142 | {
143 | this.encoding = Charset.forName(charsetName);
144 | }
145 | catch (IllegalCharsetNameException ex)
146 | {
147 | this.encoding = Charset.forName("UTF-8");
148 | }
149 | catch (UnsupportedCharsetException ex)
150 | {
151 | this.encoding = Charset.forName("UTF-8");
152 | }
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/xml/global_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
12 |
18 |
19 |
22 |
28 |
29 |
32 |
38 |
39 |
42 |
48 |
49 |
61 |
67 |
68 |
71 |
77 |
78 |
81 |
87 |
99 |
111 |
117 |
123 |
129 |
135 |
136 |
139 |
145 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/WorldDbAdapter.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import android.content.ContentValues;
7 | import android.content.Context;
8 | import android.database.Cursor;
9 | import android.database.SQLException;
10 | import android.database.sqlite.SQLiteDatabase;
11 | import android.database.sqlite.SQLiteOpenHelper;
12 |
13 | /*
14 | * Version history:
15 | * 2 - added 'logging enabled'
16 | * 3 - added auto connect and post-login commands
17 | * 4 - added encoding
18 | * 5 - added ansiColorEnabled, removed references to autoConnect in settings
19 | */
20 | public class WorldDbAdapter
21 | {
22 | //private static final String TAG = "SQLiteOpenHelper";
23 | private static final int DATABASE_VERSION = 5;
24 |
25 | private SQLiteDatabase db;
26 | private WorldDatabaseHelper dbHelper;
27 | private Context context;
28 |
29 | public WorldDbAdapter(Context context)
30 | {
31 | this.context = context;
32 | }
33 |
34 | public WorldDbAdapter open() throws SQLException
35 | {
36 | dbHelper = new WorldDatabaseHelper(context);
37 | db = dbHelper.getWritableDatabase();
38 | return this;
39 | }
40 |
41 | public void close()
42 | {
43 | db.close();
44 | db = null;
45 |
46 | dbHelper.close();
47 | dbHelper = null;
48 | }
49 |
50 | // world added won't have a dbID because it's new
51 | public void addWorldToDatabase(World world)
52 | {
53 | long newID = db.insert("tblWorld", null, world.getContentValues());
54 | addPostLoginCommandsToDatabase((int) newID, world.postLoginCommands);
55 | }
56 |
57 | public void deleteWorldFromDatabase(long id)
58 | {
59 | db.execSQL("DELETE FROM tblWorld WHERE _id = " + id + ";");
60 | db.execSQL("DELETE FROM tblWorldPostLoginCommand WHERE _id = " + id + ";");
61 | }
62 |
63 | public World[] getAllWorlds()
64 | {
65 | World[] dbWorlds = new World[0];
66 | Cursor cursor = db.query("tblWorld", new String[] {"_id", "name", "host", "port", "loggingEnabled", "ansiColorEnabled", "encoding"}, null, null, null, null, null);
67 |
68 | if (cursor != null)
69 | {
70 | int rowCount = cursor.getCount();
71 | dbWorlds = new World[rowCount];
72 | cursor.moveToFirst();
73 |
74 | for (int i = 0; i < rowCount; i++)
75 | {
76 | dbWorlds[i] = new World(
77 | cursor.getInt(0),
78 | cursor.getString(1),
79 | cursor.getString(2),
80 | cursor.getInt(3),
81 | cursor.getInt(4) > 0 ? true : false,
82 | cursor.getInt(5) > 0 ? true : false,
83 | cursor.getString(6),
84 | getPostLoginCommandsForWorldFromDatabase(cursor.getInt(0)));
85 | cursor.moveToNext();
86 | }
87 |
88 | cursor.close();
89 | cursor = null;
90 | }
91 |
92 | return dbWorlds;
93 | }
94 |
95 | public World getWorld(int id)
96 | {
97 | Cursor cursor = db.query(true, "tblWorld", new String[] {"_id", "name", "host", "port", "loggingEnabled", "ansiColorEnabled", "encoding"}, "_id = " + id, null, null, null, null, null);
98 | World world;
99 |
100 | if (cursor != null)
101 | cursor.moveToFirst();
102 | else
103 | return null;
104 |
105 | world = new World(
106 | cursor.getInt(0),
107 | cursor.getString(1),
108 | cursor.getString(2),
109 | cursor.getInt(3),
110 | cursor.getInt(4) > 0 ? true : false,
111 | cursor.getInt(5) > 0 ? true : false,
112 | cursor.getString(6),
113 | getPostLoginCommandsForWorldFromDatabase(id));
114 |
115 | cursor.close();
116 | cursor = null;
117 |
118 | return world;
119 | }
120 |
121 | public void updateWorldInDatabase(World world)
122 | {
123 | ContentValues cv = world.getContentValues();
124 | db.update("tblWorld", cv, "_id = " + world.dbID, null);
125 | addPostLoginCommandsToDatabase(world.dbID, world.postLoginCommands);
126 | }
127 |
128 | private void addPostLoginCommandsToDatabase(int worldID, List postLoginCommands)
129 | {
130 | db.execSQL("DELETE FROM tblWorldPostLoginCommand WHERE _id = " + worldID);
131 |
132 | for (String cmd : postLoginCommands)
133 | {
134 | ContentValues commands = new ContentValues(2);
135 | commands.put("_id", worldID);
136 | commands.put("command", cmd);
137 | db.insert("tblWorldPostLoginCommand", null, commands);
138 | }
139 | }
140 |
141 | private List getPostLoginCommandsForWorldFromDatabase(int worldID)
142 | {
143 | List postLoginCommands = new ArrayList();
144 |
145 | Cursor cursor = db.query(true, "tblWorldPostLoginCommand", new String[] {"command"}, "_id = " + worldID, null, null, null, null, null);
146 | if (cursor != null)
147 | {
148 | int rowCount = cursor.getCount();
149 | cursor.moveToFirst();
150 |
151 | for (int i = 0; i < rowCount; i++)
152 | {
153 | postLoginCommands.add(cursor.getString(0));
154 | cursor.moveToNext();
155 | }
156 | }
157 |
158 | cursor.close();
159 | cursor = null;
160 |
161 | return postLoginCommands;
162 | }
163 |
164 | private static class WorldDatabaseHelper extends SQLiteOpenHelper
165 | {
166 | WorldDatabaseHelper(Context context)
167 | {
168 | super(context, "tblWorld", null, DATABASE_VERSION);
169 | }
170 |
171 | @Override
172 | public void onCreate(SQLiteDatabase db)
173 | {
174 | db.execSQL("CREATE TABLE tblWorld (_id integer primary key autoincrement, name text, host text, port integer, loggingEnabled integer default 0, autoConnect integer default 0, ansiColorEnabled integer default 1, encoding text default 'UTF-8');");
175 | db.execSQL("CREATE TABLE tblWorldPostLoginCommand (_id integer primary key, command text);");
176 | }
177 |
178 | @Override
179 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
180 | {
181 | if (oldVersion < 2)
182 | db.execSQL("ALTER TABLE tblWorld ADD loggingEnabled integer DEFAULT 0;");
183 |
184 | if (oldVersion < 3)
185 | {
186 | db.execSQL("ALTER TABLE tblWorld ADD autoConnect integer DEFAULT 0;");
187 | db.execSQL("CREATE TABLE tblWorldPostLoginCommand (_id integer primary key, command text);");
188 | }
189 |
190 | if (oldVersion < 4)
191 | {
192 | db.execSQL("ALTER TABLE tblWorld ADD encoding text DEFAULT 'UTF-8';");
193 | }
194 |
195 | if (oldVersion < 5)
196 | {
197 | db.execSQL("ALTER TABLE tblWorld ADD ansiColorEnabled integer DEFAULT 1;");
198 | }
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/ConsoleTextHistory.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.FileInputStream;
5 | import java.io.FileOutputStream;
6 | import java.io.IOException;
7 | import java.io.InputStreamReader;
8 | import java.io.PrintWriter;
9 | import java.util.LinkedList;
10 |
11 | import org.codehaus.jackson.map.ObjectMapper;
12 |
13 | import android.text.Spannable;
14 | import android.text.SpannableStringBuilder;
15 | import android.text.style.CharacterStyle;
16 | import android.util.Log;
17 |
18 | public class ConsoleTextHistory
19 | {
20 | private static final String TAG = "ConsoleTextHistory";
21 | private static final ObjectMapper mapper = new ObjectMapper();
22 |
23 | private LinkedList _items;
24 | private int _maximumSize;
25 | private boolean _lastLineComplete; // does previous line end with \n
26 |
27 | public ConsoleTextHistory(int maxLength)
28 | {
29 | _items = new LinkedList();
30 | _maximumSize = maxLength;
31 | _lastLineComplete = false;
32 | }
33 |
34 | public void add(CharSequence characters)
35 | {
36 | if (_items.size() == 0 || _lastLineComplete)
37 | {
38 | _items.add(new SpannableStringBuilder(characters));
39 | adjustSize();
40 | }
41 | else
42 | _items.getLast().append(characters);
43 |
44 | if (characters.length() == 0)
45 | _lastLineComplete = false;
46 | else
47 | _lastLineComplete = (characters.charAt(characters.length() - 1) == '\n');
48 | }
49 |
50 | public void setMaximumSize(int newMaximumSize)
51 | {
52 | _maximumSize = newMaximumSize;
53 |
54 | adjustSize();
55 | }
56 |
57 | // styleStream may be null if file doesn't exist
58 | public SpannableStringBuilder loadFromFile(FileInputStream fileStream, FileInputStream styleJacksonStream)
59 | {
60 | SpannableStringBuilder sb = new SpannableStringBuilder();
61 | BufferedReader br = null;
62 |
63 | try
64 | {
65 | String line;
66 | br = new BufferedReader(new InputStreamReader(fileStream));
67 | //int lineNum = 0;
68 |
69 | try
70 | {
71 | while ((line = br.readLine()) != null)
72 | {
73 | line += "\n";
74 |
75 | add(line);
76 | //lineNum++;
77 | }
78 | }
79 | catch (IOException ex)
80 | {
81 | Log.e(TAG, "IOException trying to load console text history for world.");
82 | Log.e(TAG, ex.toString());
83 | }
84 | }
85 | finally
86 | {
87 | try
88 | {
89 | br.close();
90 | }
91 | catch (Exception ex) {}
92 | }
93 |
94 | LineStyleInfo[] lsiList = null;
95 |
96 |
97 | if (styleJacksonStream != null)
98 | {
99 | try
100 | {
101 | lsiList = mapper.readValue(styleJacksonStream, LineStyleInfo[].class);
102 | }
103 | catch (Exception ex)
104 | {
105 | Log.e(TAG, "Error occured reading Jackson JSON file: " + ex.toString());
106 | }
107 | }
108 |
109 | if (lsiList != null)
110 | {
111 | for (LineStyleInfo lsi : lsiList)
112 | {
113 | if (lsi.lineNumber < _items.size() && lsi.start >= 0
114 | && lsi.end < _items.get(lsi.lineNumber).length())
115 | {
116 | _items.get(lsi.lineNumber).setSpan(AnsiUtility.getStyleFromAnsiCode(lsi.ansiCode, false),
117 | lsi.start, lsi.end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
118 | }
119 | else
120 | {
121 | Log.w(TAG, "Invalid span in history: " + "Line: " + lsi.lineNumber + " Start: "
122 | + lsi.start + " End: " + lsi.end);
123 |
124 | if (lsi.lineNumber > _items.size())
125 | Log.w(TAG, _items.size() + " lines in history, span is for line " + lsi.lineNumber);
126 | else if (lsi.start < 0)
127 | Log.w(TAG, "span started at character " + lsi.start);
128 | else if (lsi.end >= _items.get(lsi.lineNumber).length())
129 | Log.w(TAG,
130 | "span ends at " + lsi.end + " but line is only "
131 | + _items.get(lsi.lineNumber).length());
132 | }
133 | }
134 | }
135 |
136 | for (SpannableStringBuilder ssb : _items)
137 | sb.append(ssb);
138 |
139 | return sb;
140 | }
141 |
142 | // Returns whether or not there was anything to write
143 | public boolean writeToFiles(FileOutputStream textFileStream, FileOutputStream styleJacksonStream)
144 | {
145 | if (_items.size() > 0)
146 | {
147 | PrintWriter textPw = null;
148 | LinkedList allStyles = new LinkedList();
149 |
150 | try
151 | {
152 | textPw = new PrintWriter(textFileStream);
153 |
154 | int lineNum = 0;
155 | String s;
156 | CharacterStyle[] lineSpans;
157 |
158 | for (SpannableStringBuilder ssb : _items)
159 | {
160 | s = ssb.toString();
161 | textPw.print(s);
162 |
163 | lineSpans = ssb.getSpans(0, s.length() - 1, CharacterStyle.class);
164 |
165 | for (CharacterStyle cs : lineSpans)
166 | {
167 | LineStyleInfo lsi = new LineStyleInfo();
168 |
169 | lsi.lineNumber = lineNum;
170 | lsi.start = ssb.getSpanStart(cs);
171 | lsi.end = ssb.getSpanEnd(cs);
172 | lsi.ansiCode = AnsiUtility.getAnsiCodeFromStyle(cs);
173 |
174 | allStyles.add(lsi);
175 | }
176 |
177 | lineNum++;
178 | }
179 | }
180 | finally
181 | {
182 | try
183 | {
184 | textPw.close();
185 | }
186 | catch (Exception ex) {}
187 | }
188 |
189 | try
190 | {
191 | LineStyleInfo[] lsiArray = allStyles.toArray(new LineStyleInfo[0]);
192 | mapper.writeValue(styleJacksonStream, lsiArray);
193 | }
194 | catch (Exception ex)
195 | {
196 | Log.e(TAG, "Error writing jackson JSON to file: " + ex.toString());
197 | }
198 |
199 | return true;
200 | }
201 | else
202 | return false;
203 | }
204 |
205 | private void adjustSize()
206 | {
207 | int currentSize = _items.size();
208 | int diff = currentSize - _maximumSize;
209 |
210 | // Clear list
211 | if (diff > 0)
212 | _items.subList(0, currentSize - _maximumSize).clear();
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/TcpConnection.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStreamReader;
5 | import java.io.PrintWriter;
6 | import java.net.Socket;
7 | import java.net.SocketTimeoutException;
8 | import java.nio.charset.Charset;
9 |
10 | // An individual connection to a world
11 | class TcpConnection extends Thread
12 | {
13 | //private String tag;
14 | private int connectionStatus = WorldConnectionService.STATUS_NOT_CONNECTED;
15 | private Object statusLock = new Object();
16 | private World world;
17 | private Socket socket;
18 | private MessagesToWorldProcessor messagesToWorldProcessor;
19 | private BlockingQueue messagesFromWorldQueue;
20 | private BlockingQueue messagesToWorldQueue;
21 |
22 | public TcpConnection(World world, BlockingQueue messagesFromWorldQueue, BlockingQueue messagesToWorldQueue)
23 | {
24 | this.world = world;
25 | this.messagesFromWorldQueue = messagesFromWorldQueue;
26 | this.messagesToWorldQueue = messagesToWorldQueue;
27 |
28 | //tag = "TcpConnection " + world.getHostAsString();
29 | }
30 |
31 | public Charset getEncoding()
32 | {
33 | return world.encoding;
34 | }
35 |
36 | public int getID()
37 | {
38 | return world.dbID;
39 | }
40 |
41 | public int getStatus()
42 | {
43 | synchronized (statusLock)
44 | {
45 | return connectionStatus;
46 | }
47 | }
48 |
49 | public void setStatus(int newStatus)
50 | {
51 | synchronized (statusLock)
52 | {
53 | connectionStatus = newStatus;
54 | }
55 | }
56 |
57 | public void forceDisconnect()
58 | {
59 | setStatus(WorldConnectionService.STATUS_DISCONNECTING);
60 |
61 | if (socket != null)
62 | {
63 | // only way to interrupt Java socket waiting on read input
64 | try
65 | {
66 | // doing this first = android work-around for bug
67 | socket.shutdownInput();
68 | }
69 | catch (IOException ex) {}
70 | catch (NullPointerException ex) {}
71 |
72 | try
73 | {
74 | socket.close();
75 | }
76 | catch (IOException ex) {}
77 | catch (NullPointerException ex) {}
78 | }
79 | }
80 |
81 | @Override
82 | public void run()
83 | {
84 | InputStreamReader in;
85 | PrintWriter out;
86 |
87 | try
88 | {
89 | setStatus(WorldConnectionService.STATUS_CONNECTING);
90 | sendMessage(WorldMessage.MESSAGE_TYPE_STATUS_CHANGE, WorldConnectionService.STATUS_CONNECTING, null);
91 |
92 | socket = new Socket(world.host, world.port);
93 | socket.setSoTimeout(120000); // 2 minutes
94 | in = new InputStreamReader(socket.getInputStream(), world.encoding);
95 | out = new PrintWriter(socket.getOutputStream(), true);
96 |
97 | setStatus( WorldConnectionService.STATUS_CONNECTED);
98 | sendMessage(WorldMessage.MESSAGE_TYPE_STATUS_CHANGE, WorldConnectionService.STATUS_CONNECTED, null);
99 | }
100 | catch (IOException ex)
101 | {
102 | setStatus(WorldConnectionService.STATUS_NOT_CONNECTED);
103 | sendMessage(WorldMessage.MESSAGE_TYPE_ERROR, WorldConnectionService.STATUS_NOT_CONNECTED, "Unable to connect to world: " + ex.toString());
104 | sendMessage(WorldMessage.MESSAGE_TYPE_STATUS_CHANGE, WorldConnectionService.STATUS_NOT_CONNECTED, null);
105 | return;
106 | }
107 |
108 | messagesToWorldProcessor = new MessagesToWorldProcessor(out);
109 | messagesToWorldProcessor.start();
110 |
111 | // This is a hack to deal with the fact that not all worlds send a newline after each message
112 | // When the buffer is empty, wait 2 minutes between idle messages. When the buffer isn't, send what's left after a second of idleness
113 | StringBuilder builder = new StringBuilder();
114 | char c;
115 |
116 | while (getStatus() == WorldConnectionService.STATUS_CONNECTED)
117 | {
118 | try
119 | {
120 | int iC = in.read();
121 | c = (char) iC;
122 |
123 | if (iC == -1)
124 | {
125 | setStatus(WorldConnectionService.STATUS_NOT_CONNECTED);
126 | }
127 | else if (c == '\n')
128 | {
129 | builder.append(c);
130 | sendMessage(WorldMessage.MESSAGE_TYPE_TEXT, WorldConnectionService.STATUS_CONNECTED, builder);
131 | builder = new StringBuilder();
132 | socket.setSoTimeout(120000); // 2 minutes
133 | }
134 | else
135 | {
136 | builder.append(c);
137 | socket.setSoTimeout(1000); // 1 second
138 | }
139 | }
140 | catch (SocketTimeoutException ex)
141 | {
142 | // Send whatever's currently in the buffer
143 |
144 | if (builder.length() > 0)
145 | {
146 | sendMessage(WorldMessage.MESSAGE_TYPE_TEXT, WorldConnectionService.STATUS_CONNECTED, builder);
147 | builder = new StringBuilder();
148 | }
149 | }
150 | catch (IOException ex)
151 | {
152 | setStatus(WorldConnectionService.STATUS_NOT_CONNECTED);
153 | }
154 | }
155 |
156 | sendMessage(WorldMessage.MESSAGE_TYPE_STATUS_CHANGE, WorldConnectionService.STATUS_NOT_CONNECTED, null);
157 | messagesToWorldProcessor.stopProcessing = true;
158 | messagesToWorldProcessor.interrupt();
159 | messagesToWorldProcessor = null;
160 |
161 | try
162 | {
163 | in.close();
164 | in = null;
165 | }
166 | catch (Exception ex) {}
167 |
168 | try
169 | {
170 | out.close();
171 | out = null;
172 | }
173 | catch (Exception ex) {}
174 |
175 | try
176 | {
177 | socket.close();
178 | socket = null;
179 | }
180 | catch (Exception ex) {}
181 | }
182 |
183 | private void sendMessage(int type, int currentStatus, CharSequence text)
184 | {
185 | messagesFromWorldQueue.addMessage(new WorldMessage(type, currentStatus, text));
186 | }
187 |
188 | // Pass messages received in queue along to activity
189 | // to stop, set stopProcessing == false and then interrupt thread
190 | class MessagesToWorldProcessor extends Thread
191 | {
192 | private PrintWriter printWriter;
193 |
194 | public volatile boolean stopProcessing = false;
195 |
196 | public MessagesToWorldProcessor(PrintWriter printWriter)
197 | {
198 | this.printWriter = printWriter;
199 | }
200 |
201 | @Override
202 | public void run()
203 | {
204 | while (!stopProcessing)
205 | {
206 | WorldMessage wMsg = messagesToWorldQueue.getMessage();
207 |
208 | if (wMsg != null)
209 | {
210 | printWriter.println(wMsg.text);
211 | printWriter.flush();
212 | }
213 | }
214 | }
215 | }
216 | }
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/layout/add_edit_world.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
14 |
20 |
21 |
30 |
38 |
48 |
56 |
66 |
74 |
85 |
93 |
101 |
102 |
112 |
120 |
130 |
131 |
140 |
147 |
148 |
158 |
165 |
166 |
167 |
175 |
183 |
190 |
191 |
192 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/WorldConnectionService.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.lang.reflect.InvocationTargetException;
4 | import java.lang.reflect.Method;
5 | import java.nio.charset.Charset;
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.HashSet;
9 |
10 | import android.app.Notification;
11 | import android.app.NotificationManager;
12 | import android.app.PendingIntent;
13 | import android.app.Service;
14 | import android.content.Context;
15 | import android.content.Intent;
16 | import android.content.SharedPreferences;
17 | import android.net.wifi.WifiManager;
18 | import android.net.wifi.WifiManager.WifiLock;
19 | import android.os.Bundle;
20 | import android.os.IBinder;
21 | import android.preference.PreferenceManager;
22 |
23 | // Service that manages open connections to worlds
24 | public class WorldConnectionService extends Service
25 | {
26 | //private static final String TAG = "WorldConnectionService";
27 |
28 | public static final int STATUS_NOT_CONNECTED = 0;
29 | public static final int STATUS_CONNECTING = 1;
30 | public static final int STATUS_CONNECTED = 2;
31 | public static final int STATUS_DISCONNECTING = 3;
32 |
33 | @SuppressWarnings("unchecked")
34 | private static final Class[] mStartForegroundSignature = new Class[] {int.class, Notification.class};
35 | @SuppressWarnings("unchecked")
36 | private static final Class[] mStopForegroundSignature = new Class[] {boolean.class};
37 |
38 | private WifiLock wifiLock = null;
39 |
40 | private NotificationManager mNM;
41 | private Notification notification;
42 | private Method mStartForeground;
43 | private Method mStopForeground;
44 | private Object[] mStartForegroundArgs = new Object[2];
45 | private Object[] mStopForegroundArgs = new Object[1];
46 |
47 | // Key = World's unique dbID, Value = connection to world
48 | private static HashMap allWorldConnections = new HashMap();
49 |
50 | @Override
51 | public void onCreate()
52 | {
53 | super.onCreate();
54 |
55 | mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
56 | try
57 | {
58 | mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature);
59 | mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature);
60 | }
61 | catch (NoSuchMethodException e)
62 | {
63 | // Running on an older platform.
64 | mStartForeground = mStopForeground = null;
65 | }
66 | }
67 |
68 | @Override
69 | // start a TCP connection to the specified world, or refresh connections depending on extras
70 | public void onStart(Intent intent, int startId)
71 | {
72 | super.onStart(intent, startId);
73 |
74 | if (intent == null)
75 | {
76 | refreshConnections();
77 | }
78 | else
79 | {
80 | Bundle extras = intent.getExtras();
81 |
82 | if (extras.containsKey("world"))
83 | {
84 | World world = (World) extras.getParcelable("world");
85 |
86 | WorldConnection worldConnection = new WorldConnection(world);
87 | allWorldConnections.put(world.dbID, worldConnection);
88 | worldConnection.tcpConnection.start();
89 |
90 | notification = new Notification(R.mipmap.ic_notification_boot, getString(R.string.service_started), System.currentTimeMillis());
91 |
92 | // Set intent to switch to current activity instead of starting a new one
93 | Intent switchToTask = new Intent(Intent.ACTION_MAIN, null, this, WorldListActivity.class);
94 | switchToTask.addCategory(Intent.CATEGORY_LAUNCHER);
95 |
96 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0, switchToTask, 0);
97 |
98 | if (allWorldConnections.size() == 1)
99 | notification.setLatestEventInfo(this, getString(R.string.service_title), String.format(getString(R.string.service_description_singular), allWorldConnections.size()), contentIntent);
100 | else
101 | notification.setLatestEventInfo(this, getString(R.string.service_title), String.format(getString(R.string.service_description_plural), allWorldConnections.size()), contentIntent);
102 |
103 | startForeground(R.string.service_started, notification);
104 |
105 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
106 |
107 | if (prefs.getBoolean("keep_wifi_awake", false))
108 | {
109 | WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
110 | wifiLock = wm.createWifiLock("mukluk");
111 | wifiLock.acquire();
112 | }
113 | }
114 | else if (extras.containsKey("refresh"))
115 | {
116 | refreshConnections();
117 | }
118 | }
119 | }
120 |
121 | public void onDestroy()
122 | {
123 | super.onDestroy();
124 |
125 | if (wifiLock != null)
126 | {
127 | wifiLock.release();
128 | wifiLock = null;
129 | }
130 |
131 | stopForeground(true);
132 |
133 | HashSet keys = new HashSet();
134 | keys.addAll(allWorldConnections.keySet());
135 |
136 | for (int id : keys)
137 | closeConnectionToWorld(id);
138 | }
139 |
140 | // returns array of 2
141 | // 0 - world -> activity messages
142 | // 1 - activity -> world messages
143 | // returns null for requests for worlds that don't exist or worlds that are disconnecting or not connected
144 | public static ArrayList> getBindInformationForConnection(int worldID)
145 | {
146 | WorldConnection conn = allWorldConnections.get(worldID);
147 |
148 | if (conn != null)
149 | {
150 | ArrayList> inAndOut = new ArrayList>(2);
151 |
152 | inAndOut.add(conn.worldToActivityQueue);
153 | inAndOut.add(conn.activityToWorldQueue);
154 |
155 | return inAndOut;
156 | }
157 | else
158 | {
159 | return null;
160 | }
161 | }
162 |
163 | public static void closeConnectionToWorld(int worldID)
164 | {
165 | if (allWorldConnections.containsKey(worldID))
166 | {
167 | WorldConnection conn = allWorldConnections.get(worldID);
168 |
169 | allWorldConnections.remove(worldID);
170 |
171 | if (conn.tcpConnection.getStatus() == STATUS_CONNECTED)
172 | {
173 | conn.tcpConnection.forceDisconnect();
174 | allWorldConnections.remove(worldID);
175 | }
176 | }
177 | }
178 |
179 | public static Charset getWorldConnectionEncoding(int worldID)
180 | {
181 | WorldConnection conn = allWorldConnections.get(worldID);
182 |
183 | if (conn == null)
184 | return null;
185 | else
186 | return conn.tcpConnection.getEncoding();
187 | }
188 |
189 | public static int getWorldConnectionStatus(int worldID)
190 | {
191 | WorldConnection conn = allWorldConnections.get(worldID);
192 |
193 | if (conn == null)
194 | return STATUS_NOT_CONNECTED;
195 | else
196 | return conn.tcpConnection.getStatus();
197 | }
198 |
199 | public static String getWorldConnectionStatusDescription(Context context, int connectionStatus)
200 | {
201 | switch (connectionStatus)
202 | {
203 | case STATUS_NOT_CONNECTED :
204 | return context.getString(R.string.status_description_not_connected);
205 | case STATUS_CONNECTING :
206 | return context.getString(R.string.status_description_connecting);
207 | case STATUS_CONNECTED :
208 | return context.getString(R.string.status_description_connected);
209 | case STATUS_DISCONNECTING:
210 | return context.getString(R.string.status_description_disconnecting);
211 | default:
212 | return context.getString(R.string.status_description_unknown);
213 | }
214 | }
215 |
216 | public void refreshConnections()
217 | {
218 | ArrayList removeThese = new ArrayList();
219 |
220 | for (WorldConnection conn : allWorldConnections.values())
221 | {
222 | if (conn.tcpConnection.getStatus() != STATUS_CONNECTING && conn.tcpConnection.getStatus() != STATUS_CONNECTED)
223 | removeThese.add(conn.tcpConnection.getID());
224 | }
225 |
226 | for (int id : removeThese)
227 | allWorldConnections.remove(id);
228 |
229 | if (allWorldConnections.size() == 0)
230 | stopSelf();
231 | else
232 | {
233 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, WorldListActivity.class), 0);
234 |
235 | notification = new Notification(R.mipmap.ic_notification_boot, getString(R.string.service_started), System.currentTimeMillis());
236 |
237 | if (allWorldConnections.size() == 1)
238 | notification.setLatestEventInfo(this, getString(R.string.service_title), String.format(getString(R.string.service_description_singular), allWorldConnections.size()), contentIntent);
239 | else
240 | notification.setLatestEventInfo(this, getString(R.string.service_title), String.format(getString(R.string.service_description_plural), allWorldConnections.size()), contentIntent);
241 |
242 | mNM.notify(R.string.service_started, notification);
243 | }
244 | }
245 |
246 | @Override
247 | public IBinder onBind(Intent arg0)
248 | {
249 | // Not used
250 | return null;
251 | }
252 |
253 | // queues need to be accessed before the thread may have necessarily created them
254 | class WorldConnection
255 | {
256 | public BlockingQueue worldToActivityQueue;
257 | public BlockingQueue activityToWorldQueue;
258 | public TcpConnection tcpConnection;
259 |
260 | public WorldConnection(World world)
261 | {
262 | worldToActivityQueue = new BlockingQueue();
263 | activityToWorldQueue = new BlockingQueue();
264 | tcpConnection = new TcpConnection(world, worldToActivityQueue, activityToWorldQueue);
265 | }
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Android Studio
2 | # Built application files
3 | *.apk
4 | *.aar
5 | *.ap_
6 | *.aab
7 |
8 | # Files for the ART/Dalvik VM
9 | *.dex
10 |
11 | # Java class files
12 | *.class
13 |
14 | # Generated files
15 | bin/
16 | gen/
17 | out/
18 | # Uncomment the following line in case you need and you don't have the release build type files in your app
19 | # release/
20 |
21 | # Gradle files
22 | .gradle/
23 | build/
24 |
25 | # Local configuration file (sdk path, etc)
26 | local.properties
27 |
28 | # Proguard folder generated by Eclipse
29 | proguard/
30 |
31 | # Log Files
32 | *.log
33 |
34 | # Android Studio Navigation editor temp files
35 | .navigation/
36 |
37 | # Android Studio captures folder
38 | captures/
39 |
40 | # IntelliJ
41 | *.iml
42 | .idea/workspace.xml
43 | .idea/tasks.xml
44 | .idea/gradle.xml
45 | .idea/assetWizardSettings.xml
46 | .idea/dictionaries
47 | .idea/libraries
48 | # Android Studio 3 in .gitignore file.
49 | .idea/caches
50 | .idea/modules.xml
51 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
52 | .idea/navEditor.xml
53 |
54 | # Keystore files
55 | # Uncomment the following lines if you do not want to check your keystore files in.
56 | #*.jks
57 | #*.keystore
58 |
59 | # External native build folder generated in Android Studio 2.2 and later
60 | .externalNativeBuild
61 | .cxx/
62 |
63 | # Google Services (e.g. APIs or Firebase)
64 | # google-services.json
65 |
66 | # Freeline
67 | freeline.py
68 | freeline/
69 | freeline_project_description.json
70 |
71 | # fastlane
72 | fastlane/report.xml
73 | fastlane/Preview.html
74 | fastlane/screenshots
75 | fastlane/test_output
76 | fastlane/readme.md
77 |
78 | # Version control
79 | vcs.xml
80 |
81 | # lint
82 | lint/intermediates/
83 | lint/generated/
84 | lint/outputs/
85 | lint/tmp/
86 | # lint/reports/
87 |
88 | # Android Profiling
89 | *.hprof
90 |
91 | ## Windows
92 | # Windows thumbnail cache files
93 | Thumbs.db
94 | Thumbs.db:encryptable
95 | ehthumbs.db
96 | ehthumbs_vista.db
97 |
98 | # Dump file
99 | *.stackdump
100 |
101 | # Folder config file
102 | [Dd]esktop.ini
103 |
104 | # Recycle Bin used on file shares
105 | $RECYCLE.BIN/
106 |
107 | # Windows Installer files
108 | *.cab
109 | *.msi
110 | *.msix
111 | *.msm
112 | *.msp
113 |
114 | # Windows shortcuts
115 | *.lnk
116 |
117 | ## Visual Studio
118 | ## Ignore Visual Studio temporary files, build results, and
119 | ## files generated by popular Visual Studio add-ons.
120 | ##
121 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
122 |
123 | # User-specific files
124 | *.rsuser
125 | *.suo
126 | *.user
127 | *.userosscache
128 | *.sln.docstates
129 |
130 | # User-specific files (MonoDevelop/Xamarin Studio)
131 | *.userprefs
132 |
133 | # Mono auto generated files
134 | mono_crash.*
135 |
136 | # Build results
137 | [Dd]ebug/
138 | [Dd]ebugPublic/
139 | [Rr]elease/
140 | [Rr]eleases/
141 | x64/
142 | x86/
143 | [Ww][Ii][Nn]32/
144 | [Aa][Rr][Mm]/
145 | [Aa][Rr][Mm]64/
146 | bld/
147 | [Bb]in/
148 | [Oo]bj/
149 | [Ll]og/
150 | [Ll]ogs/
151 |
152 | # Visual Studio 2015/2017 cache/options directory
153 | .vs/
154 | # Uncomment if you have tasks that create the project's static files in wwwroot
155 | #wwwroot/
156 |
157 | # Visual Studio 2017 auto generated files
158 | Generated\ Files/
159 |
160 | # MSTest test Results
161 | [Tt]est[Rr]esult*/
162 | [Bb]uild[Ll]og.*
163 |
164 | # NUnit
165 | *.VisualState.xml
166 | TestResult.xml
167 | nunit-*.xml
168 |
169 | # Build Results of an ATL Project
170 | [Dd]ebugPS/
171 | [Rr]eleasePS/
172 | dlldata.c
173 |
174 | # Benchmark Results
175 | BenchmarkDotNet.Artifacts/
176 |
177 | # .NET Core
178 | project.lock.json
179 | project.fragment.lock.json
180 | artifacts/
181 |
182 | # ASP.NET Scaffolding
183 | ScaffoldingReadMe.txt
184 |
185 | # StyleCop
186 | StyleCopReport.xml
187 |
188 | # Files built by Visual Studio
189 | *_i.c
190 | *_p.c
191 | *_h.h
192 | *.ilk
193 | *.meta
194 | *.obj
195 | *.iobj
196 | *.pch
197 | *.pdb
198 | *.ipdb
199 | *.pgc
200 | *.pgd
201 | *.rsp
202 | *.sbr
203 | *.tlb
204 | *.tli
205 | *.tlh
206 | *.tmp
207 | *.tmp_proj
208 | *_wpftmp.csproj
209 | *.log
210 | *.tlog
211 | *.vspscc
212 | *.vssscc
213 | .builds
214 | *.pidb
215 | *.svclog
216 | *.scc
217 |
218 | # Chutzpah Test files
219 | _Chutzpah*
220 |
221 | # Visual C++ cache files
222 | ipch/
223 | *.aps
224 | *.ncb
225 | *.opendb
226 | *.opensdf
227 | *.sdf
228 | *.cachefile
229 | *.VC.db
230 | *.VC.VC.opendb
231 |
232 | # Visual Studio profiler
233 | *.psess
234 | *.vsp
235 | *.vspx
236 | *.sap
237 |
238 | # Visual Studio Trace Files
239 | *.e2e
240 |
241 | # TFS 2012 Local Workspace
242 | $tf/
243 |
244 | # Guidance Automation Toolkit
245 | *.gpState
246 |
247 | # ReSharper is a .NET coding add-in
248 | _ReSharper*/
249 | *.[Rr]e[Ss]harper
250 | *.DotSettings.user
251 |
252 | # TeamCity is a build add-in
253 | _TeamCity*
254 |
255 | # DotCover is a Code Coverage Tool
256 | *.dotCover
257 |
258 | # AxoCover is a Code Coverage Tool
259 | .axoCover/*
260 | !.axoCover/settings.json
261 |
262 | # Coverlet is a free, cross platform Code Coverage Tool
263 | coverage*.json
264 | coverage*.xml
265 | coverage*.info
266 |
267 | # Visual Studio code coverage results
268 | *.coverage
269 | *.coveragexml
270 |
271 | # NCrunch
272 | _NCrunch_*
273 | .*crunch*.local.xml
274 | nCrunchTemp_*
275 |
276 | # MightyMoose
277 | *.mm.*
278 | AutoTest.Net/
279 |
280 | # Web workbench (sass)
281 | .sass-cache/
282 |
283 | # Installshield output folder
284 | [Ee]xpress/
285 |
286 | # DocProject is a documentation generator add-in
287 | DocProject/buildhelp/
288 | DocProject/Help/*.HxT
289 | DocProject/Help/*.HxC
290 | DocProject/Help/*.hhc
291 | DocProject/Help/*.hhk
292 | DocProject/Help/*.hhp
293 | DocProject/Help/Html2
294 | DocProject/Help/html
295 |
296 | # Click-Once directory
297 | publish/
298 |
299 | # Publish Web Output
300 | *.[Pp]ublish.xml
301 | *.azurePubxml
302 | # Note: Comment the next line if you want to checkin your web deploy settings,
303 | # but database connection strings (with potential passwords) will be unencrypted
304 | *.pubxml
305 | *.publishproj
306 |
307 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
308 | # checkin your Azure Web App publish settings, but sensitive information contained
309 | # in these scripts will be unencrypted
310 | PublishScripts/
311 |
312 | # NuGet Packages
313 | *.nupkg
314 | # NuGet Symbol Packages
315 | *.snupkg
316 | # The packages folder can be ignored because of Package Restore
317 | **/[Pp]ackages/*
318 | # except build/, which is used as an MSBuild target.
319 | !**/[Pp]ackages/build/
320 | # Uncomment if necessary however generally it will be regenerated when needed
321 | #!**/[Pp]ackages/repositories.config
322 | # NuGet v3's project.json files produces more ignorable files
323 | *.nuget.props
324 | *.nuget.targets
325 |
326 | # Microsoft Azure Build Output
327 | csx/
328 | *.build.csdef
329 |
330 | # Microsoft Azure Emulator
331 | ecf/
332 | rcf/
333 |
334 | # Windows Store app package directories and files
335 | AppPackages/
336 | BundleArtifacts/
337 | Package.StoreAssociation.xml
338 | _pkginfo.txt
339 | *.appx
340 | *.appxbundle
341 | *.appxupload
342 |
343 | # Visual Studio cache files
344 | # files ending in .cache can be ignored
345 | *.[Cc]ache
346 | # but keep track of directories ending in .cache
347 | !?*.[Cc]ache/
348 |
349 | # Others
350 | ClientBin/
351 | ~$*
352 | *~
353 | *.dbmdl
354 | *.dbproj.schemaview
355 | *.jfm
356 | *.pfx
357 | *.publishsettings
358 | orleans.codegen.cs
359 |
360 | # Including strong name files can present a security risk
361 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
362 | #*.snk
363 |
364 | # Since there are multiple workflows, uncomment next line to ignore bower_components
365 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
366 | #bower_components/
367 |
368 | # RIA/Silverlight projects
369 | Generated_Code/
370 |
371 | # Backup & report files from converting an old project file
372 | # to a newer Visual Studio version. Backup files are not needed,
373 | # because we have git ;-)
374 | _UpgradeReport_Files/
375 | Backup*/
376 | UpgradeLog*.XML
377 | UpgradeLog*.htm
378 | ServiceFabricBackup/
379 | *.rptproj.bak
380 |
381 | # SQL Server files
382 | *.mdf
383 | *.ldf
384 | *.ndf
385 |
386 | # Business Intelligence projects
387 | *.rdl.data
388 | *.bim.layout
389 | *.bim_*.settings
390 | *.rptproj.rsuser
391 | *- [Bb]ackup.rdl
392 | *- [Bb]ackup ([0-9]).rdl
393 | *- [Bb]ackup ([0-9][0-9]).rdl
394 |
395 | # Microsoft Fakes
396 | FakesAssemblies/
397 |
398 | # GhostDoc plugin setting file
399 | *.GhostDoc.xml
400 |
401 | # Node.js Tools for Visual Studio
402 | .ntvs_analysis.dat
403 | node_modules/
404 |
405 | # Visual Studio 6 build log
406 | *.plg
407 |
408 | # Visual Studio 6 workspace options file
409 | *.opt
410 |
411 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
412 | *.vbw
413 |
414 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
415 | *.vbp
416 |
417 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
418 | *.dsw
419 | *.dsp
420 |
421 | # Visual Studio 6 technical files
422 | *.ncb
423 | *.aps
424 |
425 | # Visual Studio LightSwitch build output
426 | **/*.HTMLClient/GeneratedArtifacts
427 | **/*.DesktopClient/GeneratedArtifacts
428 | **/*.DesktopClient/ModelManifest.xml
429 | **/*.Server/GeneratedArtifacts
430 | **/*.Server/ModelManifest.xml
431 | _Pvt_Extensions
432 |
433 | # Paket dependency manager
434 | .paket/paket.exe
435 | paket-files/
436 |
437 | # FAKE - F# Make
438 | .fake/
439 |
440 | # CodeRush personal settings
441 | .cr/personal
442 |
443 | # Python Tools for Visual Studio (PTVS)
444 | __pycache__/
445 | *.pyc
446 |
447 | # Cake - Uncomment if you are using it
448 | # tools/**
449 | # !tools/packages.config
450 |
451 | # Tabs Studio
452 | *.tss
453 |
454 | # Telerik's JustMock configuration file
455 | *.jmconfig
456 |
457 | # BizTalk build output
458 | *.btp.cs
459 | *.btm.cs
460 | *.odx.cs
461 | *.xsd.cs
462 |
463 | # OpenCover UI analysis results
464 | OpenCover/
465 |
466 | # Azure Stream Analytics local run output
467 | ASALocalRun/
468 |
469 | # MSBuild Binary and Structured Log
470 | *.binlog
471 |
472 | # NVidia Nsight GPU debugger configuration file
473 | *.nvuser
474 |
475 | # MFractors (Xamarin productivity tool) working folder
476 | .mfractor/
477 |
478 | # Local History for Visual Studio
479 | .localhistory/
480 |
481 | # Visual Studio History (VSHistory) files
482 | .vshistory/
483 |
484 | # BeatPulse healthcheck temp database
485 | healthchecksdb
486 |
487 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
488 | MigrationBackup/
489 |
490 | # Ionide (cross platform F# VS Code tools) working folder
491 | .ionide/
492 |
493 | # Fody - auto-generated XML schema
494 | FodyWeavers.xsd
495 |
496 | # VS Code files for those working on multiple tools
497 | .vscode/*
498 | !.vscode/settings.json
499 | !.vscode/tasks.json
500 | !.vscode/launch.json
501 | !.vscode/extensions.json
502 | *.code-workspace
503 |
504 | # Local History for Visual Studio Code
505 | .history/
506 |
507 | # Windows Installer files from build outputs
508 | *.cab
509 | *.msi
510 | *.msix
511 | *.msm
512 | *.msp
513 |
514 | # JetBrains Rider
515 | *.sln.iml
516 |
517 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/AddEditWorldActivity.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.content.Context;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.os.Bundle;
9 | import android.text.Editable;
10 | import android.text.TextWatcher;
11 | import android.view.KeyEvent;
12 | import android.view.View;
13 | import android.view.View.OnClickListener;
14 | import android.widget.AdapterView;
15 | import android.widget.ArrayAdapter;
16 | import android.widget.Button;
17 | import android.widget.CheckBox;
18 | import android.widget.CompoundButton;
19 | import android.widget.EditText;
20 | import android.widget.Spinner;
21 | import android.widget.AdapterView.OnItemSelectedListener;
22 |
23 | public class AddEditWorldActivity extends Activity
24 | {
25 | //private static final String TAG = "AddEditWorldActivity";
26 | public static final int ADD_WORLD = 1;
27 | public static final int EDIT_WORLD = 2;
28 |
29 | private boolean settingsChanged;
30 |
31 | private Context context;
32 | private World worldToEdit = null;
33 | private EditText txtWorldName;
34 | private EditText txtWorldHost;
35 | private EditText txtWorldPort;
36 | private Spinner spnEncoding;
37 | private CheckBox chkLogging;
38 | private CheckBox chkAnsiColor;
39 | private EditText txtPostLoginCommand;
40 | private Button saveButton;
41 | private Button cancelButton;
42 |
43 | private ArrayAdapter adapter;
44 | private String previousEncodingSetting = null;
45 |
46 | // Called when "OK" is clicked on the save confirmation box
47 | DialogInterface.OnClickListener saveChangesOkayListener = new DialogInterface.OnClickListener()
48 | {
49 | public void onClick(DialogInterface dialog, int which)
50 | {
51 | saveChanges();
52 | }
53 | };
54 |
55 | // Called when "Don't Save" is clicked on the save confirmation box
56 | DialogInterface.OnClickListener saveChangesDontSaveListener = new DialogInterface.OnClickListener()
57 | {
58 | public void onClick(DialogInterface dialog, int which)
59 | {
60 | cancelChanges();
61 | }
62 | };
63 |
64 | // Called when "Cancel" is clicked on the save confirmation box
65 | DialogInterface.OnClickListener saveChangesCancelListener = new DialogInterface.OnClickListener()
66 | {
67 | public void onClick(DialogInterface dialog, int which)
68 | {
69 | // don't do anything
70 | }
71 | };
72 |
73 | // Called when text is changed in name, host or post
74 | private TextWatcher updateSaveButtonStatus = new TextWatcher()
75 | {
76 | @Override
77 | public void afterTextChanged(Editable s)
78 | {
79 | toggleButtons();
80 | }
81 |
82 | @Override
83 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
84 |
85 | @Override
86 | public void onTextChanged(CharSequence s, int start, int before, int count) {}
87 | };
88 |
89 | // Called when anything text-based is changed
90 | private TextWatcher updateChangedStatus = new TextWatcher()
91 | {
92 | @Override
93 | public void afterTextChanged(Editable s)
94 | {
95 | settingsChanged = true;
96 | }
97 |
98 | @Override
99 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
100 |
101 | @Override
102 | public void onTextChanged(CharSequence s, int start, int before, int count) {}
103 | };
104 |
105 | @SuppressWarnings("unchecked")
106 | @Override
107 | public void onCreate(Bundle savedInstanceState)
108 | {
109 | super.onCreate(savedInstanceState);
110 | setContentView(R.layout.add_edit_world);
111 |
112 | context = getApplicationContext();
113 |
114 | saveButton = (Button) findViewById(R.id.button_save_editing);
115 | saveButton.setOnClickListener(
116 | new OnClickListener()
117 | {
118 | @Override
119 | public void onClick(View v)
120 | {
121 | saveChanges();
122 | }
123 | });
124 |
125 | cancelButton = (Button) findViewById(R.id.button_cancel_editing);
126 | cancelButton.setOnClickListener(
127 | new OnClickListener()
128 | {
129 | @Override
130 | public void onClick(View v)
131 | {
132 | cancelChanges();
133 | }
134 | });
135 |
136 | txtWorldName = (EditText) findViewById(R.id.text_world_name);
137 | txtWorldName.addTextChangedListener(updateSaveButtonStatus);
138 | txtWorldName.addTextChangedListener(updateChangedStatus);
139 |
140 | txtWorldHost = (EditText) findViewById(R.id.text_world_address);
141 | txtWorldHost.addTextChangedListener(updateSaveButtonStatus);
142 | txtWorldHost.addTextChangedListener(updateChangedStatus);
143 |
144 | txtWorldPort = (EditText) findViewById(R.id.text_world_port);
145 | txtWorldPort.addTextChangedListener(updateSaveButtonStatus);
146 | txtWorldPort.addTextChangedListener(updateChangedStatus);
147 |
148 | adapter = new ArrayAdapter(context, android.R.layout.simple_spinner_item, Utility.getSupportedCharsetNames());
149 | adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
150 |
151 | spnEncoding = (Spinner) findViewById(R.id.spinner_encoding);
152 | spnEncoding.setAdapter(adapter);
153 | spnEncoding.setOnItemSelectedListener(new OnItemSelectedListener()
154 | {
155 | @Override
156 | public void onItemSelected(AdapterView> arg0, View arg1, int arg2, long arg3)
157 | {
158 | int newPos = arg2;
159 |
160 | // only if this isn't a new world and the new setting does not match one on the old world
161 | if (previousEncodingSetting != null && newPos != adapter.getPosition(previousEncodingSetting))
162 | settingsChanged = true;
163 | }
164 |
165 | @Override
166 | public void onNothingSelected(AdapterView> arg0) {}
167 | });
168 |
169 | chkLogging = (CheckBox) findViewById(R.id.checkbox_logging);
170 | chkLogging.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
171 | {
172 | @Override
173 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
174 | {
175 | settingsChanged = true;
176 | toggleButtons();
177 | }
178 | });
179 |
180 | chkAnsiColor = (CheckBox) findViewById(R.id.checkbox_ansi_color);
181 | chkAnsiColor.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
182 | {
183 | @Override
184 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
185 | {
186 | settingsChanged = true;
187 | toggleButtons();
188 | }
189 | });
190 |
191 | txtPostLoginCommand = (EditText) findViewById(R.id.text_post_login_command);
192 | txtPostLoginCommand.addTextChangedListener(updateChangedStatus);
193 |
194 | Bundle extras = getIntent().getExtras();
195 |
196 | if (extras == null)
197 | {
198 | // adding a new world
199 | saveButton.setEnabled(false);
200 | spnEncoding.setSelection(adapter.getPosition("UTF-8"));
201 | chkAnsiColor.setChecked(true);
202 | }
203 | if (extras != null)
204 | {
205 | // Editing an existing world
206 | worldToEdit = (World) extras.getParcelable("world");
207 |
208 | if (worldToEdit.name != null && worldToEdit.name.length() > 0)
209 | txtWorldName.setText(worldToEdit.name);
210 |
211 | if (worldToEdit.host != null && worldToEdit.host.length() > 0)
212 | txtWorldHost.setText(worldToEdit.host);
213 |
214 | if (worldToEdit.port > 0)
215 | txtWorldPort.setText(String.valueOf(worldToEdit.port));
216 |
217 | if (worldToEdit.loggingEnabled)
218 | chkLogging.setChecked(true);
219 |
220 | if (worldToEdit.ansiColorEnabled)
221 | {
222 | chkAnsiColor.setChecked(true);
223 | }
224 |
225 | if (worldToEdit.postLoginCommands.size() > 0)
226 | txtPostLoginCommand.setText(worldToEdit.postLoginCommands.get(0));
227 |
228 | spnEncoding.setSelection(adapter.getPosition(worldToEdit.encoding.name()));
229 | previousEncodingSetting = worldToEdit.encoding.name();
230 |
231 | saveButton.setEnabled(true);
232 | }
233 | }
234 |
235 | @Override
236 | public void onResume()
237 | {
238 | super.onResume();
239 |
240 | settingsChanged = false;
241 | }
242 |
243 | @Override
244 | // intercept back button if changes made
245 | public boolean onKeyDown(int keyCode, KeyEvent event)
246 | {
247 | if (keyCode == KeyEvent.KEYCODE_BACK)
248 | {
249 | if (settingsChanged &&
250 | (txtWorldName.getText().toString().trim().length() == 0 ||
251 | txtWorldHost.getText().toString().trim().length() == 0 ||
252 | txtWorldPort.getText().toString().trim().length() == 0))
253 | {
254 | showSaveMissingDataConfirmationDialog();
255 | return false;
256 | }
257 |
258 | if (settingsChanged)
259 | {
260 | showSaveConfirmationDialog();
261 | return false;
262 | }
263 | }
264 |
265 | return super.onKeyDown(keyCode, event);
266 | }
267 |
268 | private void cancelChanges()
269 | {
270 | setResult(RESULT_CANCELED);
271 | finish();
272 | }
273 |
274 | private void saveChanges()
275 | {
276 | if (worldToEdit == null)
277 | worldToEdit = new World(); // no dbID if a brand new world. this is okay
278 |
279 | worldToEdit.name = txtWorldName.getText().toString();
280 | worldToEdit.host = txtWorldHost.getText().toString();
281 | worldToEdit.port = txtWorldPort.getText().toString().trim().length() == 0 ? 0 : Integer.parseInt(txtWorldPort.getText().toString());
282 | worldToEdit.loggingEnabled = chkLogging.isChecked();
283 | worldToEdit.ansiColorEnabled = chkAnsiColor.isChecked();
284 | worldToEdit.setCharset((String) spnEncoding.getSelectedItem());
285 |
286 | worldToEdit.postLoginCommands.clear();
287 | String postLoginCommand = txtPostLoginCommand.getText().toString().trim();
288 |
289 | if (postLoginCommand.length() > 0)
290 | {
291 | worldToEdit.postLoginCommands.add(postLoginCommand);
292 | }
293 |
294 | Bundle bundle = new Bundle();
295 | bundle.putParcelable("world", worldToEdit);
296 |
297 | Intent intent = new Intent();
298 | intent.putExtras(bundle);
299 | setResult(RESULT_OK, intent);
300 | finish();
301 | }
302 |
303 | // set the save and cancel buttons on or off depending on if all necessary data is filled out
304 | private void toggleButtons()
305 | {
306 | if (txtWorldName.getText().toString().trim().length() > 0 && txtWorldHost.getText().toString().trim().length() > 0 && txtWorldPort.getText().toString().trim().length() > 0)
307 | {
308 | saveButton.setEnabled(true);
309 | }
310 | else
311 | {
312 | saveButton.setEnabled(false);
313 | }
314 | }
315 |
316 | private void showSaveConfirmationDialog()
317 | {
318 | AlertDialog alertDialog = new AlertDialog.Builder(this).create();
319 | alertDialog.setTitle(context.getString(R.string.dialog_title_unsaved_changes));
320 | alertDialog.setMessage(String.format(context.getString(R.string.dialog_message_unsaved_changes), txtWorldName.getText().toString()));
321 | alertDialog.setButton(context.getString(R.string.button_save), saveChangesOkayListener);
322 | alertDialog.setButton2(context.getString(R.string.button_cancel), saveChangesCancelListener);
323 | alertDialog.setButton3(context.getString(R.string.button_dont_save), saveChangesDontSaveListener);
324 | alertDialog.show();
325 | }
326 |
327 | private void showSaveMissingDataConfirmationDialog()
328 | {
329 | AlertDialog alertDialog = new AlertDialog.Builder(this).create();
330 | alertDialog.setTitle(context.getString(R.string.dialog_title_missing_data_unsaved_changes));
331 | alertDialog.setMessage(context.getString(R.string.dialog_message_missing_data_unsaved_changes));
332 | alertDialog.setButton(context.getString(R.string.button_save), saveChangesOkayListener);
333 | alertDialog.setButton2(context.getString(R.string.button_cancel), saveChangesCancelListener);
334 | alertDialog.setButton3(context.getString(R.string.button_dont_save), saveChangesDontSaveListener);
335 | alertDialog.show();
336 | }
337 | }
338 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Mukluk
4 |
5 | Cancel
6 | Default
7 | Don\'t Save
8 | OK
9 | Save
10 | Global Settings
11 | %1$s added to world list.
12 | %1$s saved.
13 |
14 |
15 | Connected to %1$s world.
16 | Connected to %1$s worlds.
17 | Mukluk MUD Client
18 | Starting world connection...
19 | World connection status changed.
20 |
21 | Not connected.
22 | Connecting...
23 | Connected.
24 | Disconnecting...
25 | Unknown connection status?
26 |
27 |
28 | Disconnect
29 | Stay Connected
30 | You are currently connected to one or more worlds. Do you want to disconnect?
31 | This will clear all world text from the world window, all of your previous commands from the browsable history and all navigable URLs from the menu and can not be undone.
32 | Delete this world?
33 | Export file location:
34 | Import file location:
35 | No worlds have been created. Would you like to add one now?
36 | Disconnect From Worlds
37 | Clear %1$s Cache?
38 | Export Worlds
39 | Import Worlds
40 | Add New World
41 | No worlds have been created.
42 | Not connected.
43 | Connected.
44 | Connecting...
45 | Disconnected.
46 | About
47 | Add World
48 | Copy World
49 | Clear World Cache
50 | Delete World
51 | Edit World
52 | Export Worlds
53 | Import Worlds
54 | Please disconnect from this world before deleting it.
55 | Changes saved.
56 | Unable to write to external media. Your phone\'s SD card may be unavailable or read-only.
57 | No worlds to export.
58 | World list exported to file %1$s
59 | Unable to read from external media. There may be a problem with your phone\'s SD card.
60 | Specified file %1$s doesn\'t exist.
61 | %1$s cache cleared
62 | Can\'t connect to this world. Host and port must both be defined.
63 |
64 |
65 | Settings
66 |
67 | Appearance
68 | Background Color
69 | Text Color
70 | Command Color
71 | The quick brown fox jumped over 1,234,567,890 lazy dogs.
72 | Red
73 | Green
74 | Blue
75 | Text Size
76 | Size
77 | Full Screen
78 | Display world window full screen (hide notification bar)
79 | Auto-Say Selector
80 | Display a selector that lets you auto-say, -emote or -pose to a world
81 | On-Screen Enter Button
82 | Display an enter button next to the command box
83 | Verify History Navigation
84 | Verify navigation to previous commands if there is unsent text in the world window
85 | Disable History Navigation
86 | Disable scrolling through previous commands with finger swipe and arrow keys
87 | Hide Ad
88 | Hide the ad on the world list page
89 |
90 | Output
91 | Vibrate On Bell
92 | Vibrate the phone when a bell/alarm character is received
93 |
94 | Commands
95 | Echo Commands
96 | Echo your commands to the world window
97 | Screen Buffer Size
98 | Number of lines to keep in the world window
99 | Screen Buffer Size
100 | Number of lines to keep in the world window:
101 | Command Buffer Size
102 | Number of your previous commands to keep in the browsable history
103 | Command Buffer Size
104 | Number of your previous commands to save:
105 | URL Buffer Size
106 | Number of URLs from the world to keep in history
107 | URL Buffer Size
108 | Number of URLs to save:
109 |
110 | Device
111 | Keep Screen Awake
112 | Keep screen awake when world window is active
113 | Keep Wi-Fi Awake
114 | Keep wi-fi connection awake when connected to a world
115 |
116 |
117 | About Mukluk MUD Client
118 | Installed Version
119 | Credits
120 | © 2015 by Dan Caprine
121 | https://www.facebook.com/MuklukMudClient
122 | Legal
123 | Mukluk uses the Jackson JSON parser under the Apache 2.0 license.
124 | http://jackson.codehaus.org/
125 | Mukluk uses content from Icons8 under the Creative Commons Attribution-NoDerivs 3.0 Unported license.
126 | https://icons8.com/
127 |
128 |
129 | Edit World Details
130 | Server
131 | Save Changes
132 | Save changes to %1$s?
133 | Save Changes
134 | You have not entered a name, host and/or port for this world. Save anyway?
135 | example.com
136 | My MUD Name
137 | 12345
138 | Encoding
139 | Address
140 | World Name
141 | Port
142 | Connection
143 | Automatically Connect
144 | Post-Connection Command
145 | connect player password
146 | Miscellaneous
147 | Log to SD Card
148 | ANSI Colors Enabled
149 |
150 |
151 | World
152 | *** Mukluk is now connected. ***
153 | *** Mukluk has been disconnected from this world. ***
154 | Pause Scrolling
155 | Disable Auto-Scroll
156 | Navigate History
157 | Navigate to previous command in history? This will delete your current input.
158 | Navigate to next command in history? This will delete your current input.
159 | URL List
160 | Enter
161 | Select Auto-Command
162 | Cache
163 | Connect
164 | Disconnect
165 | Edit World
166 | Help
167 | Start Logging
168 | Stop Logging
169 | Couldn\'t reattach to connection. Try backing out of this window and reopening it.
170 | Character encoding changed. You will need to disconnect and reconnect to enable the new settings.
171 | Unable to start logging. Your phone\'s SD card may be unavailable or read-only.
172 | No longer logging.
173 | Now logging to %1$s
174 | No URLs found.
175 | This world\'s host and/or port were changed. You\'ll need to reconnect to see these changes.
176 |
177 |
178 | Console
179 |
180 | This is where text from the world is displayed. Long-press here to pause autoscrolling. Double-tap here to scan for URLs and navigate to them.
181 |
182 | Auto-Say Selector
183 |
184 | Select a value here to automatically prepend commands you send to the world with \"say\", \"pose\", etc.
185 | This selector can be hidden in the Settings menu.
186 |
187 | Enter Button
188 | Press this button to send the text in the command entry to the connected world.
189 | This button can be hidden in the Settings Menu.
190 | Command Entry
191 |
192 | Enter commands to send to the world here. You can browse your command history with the up and down arrows on your keypad (if available)
193 | or by swiping your finger left or right.
194 |
195 | Touch any item on the screen for more information.
196 |
197 |
198 | - [None]
199 | - Say
200 | - Emote
201 | - Pose
202 |
203 |
204 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/AnsiUtility.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.util.ArrayList;
4 | import java.util.regex.Matcher;
5 | import java.util.regex.Pattern;
6 |
7 | import android.graphics.Color;
8 | import android.text.Spannable;
9 | import android.text.SpannableStringBuilder;
10 | import android.text.style.BackgroundColorSpan;
11 | import android.text.style.CharacterStyle;
12 | import android.text.style.ForegroundColorSpan;
13 | import android.text.style.StrikethroughSpan;
14 | import android.text.style.StyleSpan;
15 | import android.text.style.UnderlineSpan;
16 | import android.util.Log;
17 |
18 | public abstract class AnsiUtility
19 | {
20 | private static final String TAG = "AnsiUtility";
21 |
22 | private static final Pattern ANSI_PATTERN = Pattern.compile("\\e\\[[\\d+;?]+m");
23 | private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+");
24 |
25 | public static final IndexedColors xtermColors = new IndexedColors();
26 |
27 | public static final int BLACK = Color.rgb(0, 0, 0);
28 | private static final int RED = Color.rgb(128, 0, 0);
29 | private static final int GREEN = Color.rgb(0, 128, 0);
30 | private static final int YELLOW = Color.rgb(128, 128, 0);
31 | private static final int BLUE = Color.rgb(0, 0, 128);
32 | private static final int MAGENTA = Color.rgb(128, 0, 12);
33 | private static final int CYAN = Color.rgb(0, 128, 128);
34 | private static final int GRAY = Color.rgb(192, 192, 192);
35 |
36 | private static final int DARK_GRAY = Color.rgb(128, 128, 128);
37 | private static final int BRIGHT_RED = Color.rgb(255, 0, 0);
38 | private static final int BRIGHT_GREEN = Color.rgb(0, 255, 0);
39 | private static final int BRIGHT_YELLOW = Color.rgb(255, 255, 0);
40 | private static final int BRIGHT_BLUE = Color.rgb(0, 0, 255);
41 | private static final int BRIGHT_MAGENTA = Color.rgb(255, 0, 255);
42 | private static final int BRIGHT_CYAN = Color.rgb(0, 255, 255);
43 | private static final int WHITE = Color.rgb(255, 255, 255);
44 |
45 | public static ArrayList getAnsiCodeFromStyle(CharacterStyle charStyle)
46 | {
47 | ArrayList returnStyle = new ArrayList(3);
48 |
49 | if (charStyle instanceof StyleSpan)
50 | {
51 | StyleSpan ss = (StyleSpan) charStyle;
52 | int style = ss.getStyle();
53 |
54 | if (style == android.graphics.Typeface.ITALIC)
55 | returnStyle.add(3);
56 | }
57 | else if (charStyle instanceof UnderlineSpan)
58 | {
59 | returnStyle.add(4);
60 | }
61 | else if (charStyle instanceof StrikethroughSpan)
62 | {
63 | returnStyle.add(9);
64 | }
65 | else if (charStyle instanceof ForegroundColorSpan)
66 | {
67 | ForegroundColorSpan fs = (ForegroundColorSpan) charStyle;
68 | int color = fs.getForegroundColor();
69 |
70 | if (color == BLACK)
71 | returnStyle.add(30);
72 | else if (color == RED)
73 | returnStyle.add(31);
74 | else if (color == GREEN)
75 | returnStyle.add(32);
76 | else if (color == YELLOW)
77 | returnStyle.add(33);
78 | else if (color == BLUE)
79 | returnStyle.add(34);
80 | else if (color == MAGENTA)
81 | returnStyle.add(35);
82 | else if (color == CYAN)
83 | returnStyle.add(36);
84 | else if (color == GRAY)
85 | returnStyle.add(37);
86 | else if (color == DARK_GRAY)
87 | returnStyle.add(90);
88 | else if (color == BRIGHT_RED)
89 | returnStyle.add(91);
90 | else if (color == BRIGHT_GREEN)
91 | returnStyle.add(92);
92 | else if (color == BRIGHT_YELLOW)
93 | returnStyle.add(93);
94 | else if (color == BRIGHT_BLUE)
95 | returnStyle.add(94);
96 | else if (color == BRIGHT_MAGENTA)
97 | returnStyle.add(95);
98 | else if (color == BRIGHT_CYAN)
99 | returnStyle.add(96);
100 | else if (color == WHITE)
101 | returnStyle.add(97);
102 | else
103 | {
104 | returnStyle.add(38);
105 | returnStyle.add(5);
106 | returnStyle.add(color);
107 | }
108 | }
109 | else if (charStyle instanceof BackgroundColorSpan)
110 | {
111 | BackgroundColorSpan bs = (BackgroundColorSpan) charStyle;
112 | int color = bs.getBackgroundColor();
113 |
114 | if (color == BLACK)
115 | returnStyle.add(40);
116 | else if (color == RED)
117 | returnStyle.add(41);
118 | else if (color == GREEN)
119 | returnStyle.add(42);
120 | else if (color == YELLOW)
121 | returnStyle.add(43);
122 | else if (color == BLUE)
123 | returnStyle.add(44);
124 | else if (color == MAGENTA)
125 | returnStyle.add(45);
126 | else if (color == CYAN)
127 | returnStyle.add(46);
128 | else if (color == GRAY)
129 | returnStyle.add(47);
130 | else if (color == DARK_GRAY)
131 | returnStyle.add(100);
132 | else if (color == BRIGHT_RED)
133 | returnStyle.add(101);
134 | else if (color == BRIGHT_GREEN)
135 | returnStyle.add(102);
136 | else if (color == BRIGHT_YELLOW)
137 | returnStyle.add(103);
138 | else if (color == BRIGHT_BLUE)
139 | returnStyle.add(104);
140 | else if (color == BRIGHT_MAGENTA)
141 | returnStyle.add(105);
142 | else if (color == BRIGHT_CYAN)
143 | returnStyle.add(106);
144 | else if (color == WHITE)
145 | returnStyle.add(107);
146 | else
147 | {
148 | returnStyle.add(48);
149 | returnStyle.add(5);
150 | returnStyle.add(color);
151 | }
152 | }
153 |
154 | if (returnStyle.size() == 0)
155 | returnStyle.add(-1);
156 |
157 | return returnStyle;
158 | }
159 |
160 | public static CharSequence getWithAnsiStyles(String strToConvert, boolean stripOnly)
161 | {
162 | Matcher mAnsi = ANSI_PATTERN.matcher(strToConvert);
163 | CharSequence returnText;
164 | String strippedText = mAnsi.replaceAll("");
165 |
166 | if (!stripOnly && strippedText.length() != strToConvert.length())
167 | {
168 | SpannableStringBuilder ansiString = new SpannableStringBuilder(strippedText);
169 | mAnsi = ANSI_PATTERN.matcher(strToConvert); // need to rebuild because replaceall() replaces object
170 |
171 | Matcher mNumber;
172 | String ansiGroup;
173 | int charsRemoved = 0;
174 | int stringPos = 0;
175 |
176 | ArrayList styles = new ArrayList();
177 | boolean brightOn = false;
178 |
179 | while (mAnsi.find())
180 | {
181 | int codesFound = 0;
182 |
183 | ansiGroup = mAnsi.group();
184 | mNumber = NUMBER_PATTERN.matcher(ansiGroup);
185 |
186 | while (mNumber.find())
187 | {
188 | codesFound++;
189 |
190 | try
191 | {
192 | int code = Integer.parseInt(mNumber.group());
193 |
194 | if (code == 0)
195 | {
196 | // end all active styles
197 | for (StyleInfo si : styles)
198 | {
199 | if (si.end == -1)
200 | si.end = strToConvert.indexOf(ansiGroup, stringPos) - charsRemoved;
201 | }
202 | brightOn = false;
203 | }
204 | else if (code == 1)
205 | {
206 | brightOn = true;
207 | }
208 | else if (code == 10)
209 | {
210 | // end text mods
211 | for (StyleInfo si : styles)
212 | {
213 | if (si.style instanceof StyleSpan || si.style instanceof UnderlineSpan
214 | || si.style instanceof StrikethroughSpan)
215 | si.end = strToConvert.indexOf(ansiGroup, stringPos) - charsRemoved;
216 | }
217 | brightOn = false;
218 | }
219 | else if (code == 21)
220 | {
221 | // bright bright
222 | brightOn = false;
223 | }
224 | else if (code == 23)
225 | {
226 | // end italic
227 | for (StyleInfo si : styles)
228 | {
229 | if (si.style instanceof StyleSpan
230 | && ((StyleSpan) si.style).getStyle() == android.graphics.Typeface.ITALIC)
231 | si.end = strToConvert.indexOf(ansiGroup, stringPos) - charsRemoved;
232 | }
233 | }
234 | else if (code == 24)
235 | {
236 | // end italic
237 | for (StyleInfo si : styles)
238 | {
239 | if (si.style instanceof UnderlineSpan)
240 | si.end = strToConvert.indexOf(ansiGroup, stringPos) - charsRemoved;
241 | }
242 | }
243 | else if (code == 29)
244 | {
245 | // end strikethrough
246 | for (StyleInfo si : styles)
247 | {
248 | if (si.style instanceof StrikethroughSpan)
249 | si.end = strToConvert.indexOf(ansiGroup, stringPos) - charsRemoved;
250 | }
251 | }
252 | else if (code == 38)
253 | {
254 | // color text
255 |
256 | if (mNumber.find() && Integer.parseInt(mNumber.group()) == 5 && mNumber.find())
257 | {
258 | int fgColor = Integer.parseInt(mNumber.group());
259 |
260 | if (fgColor < 256)
261 | {
262 | styles.add(new StyleInfo(new ForegroundColorSpan(
263 | xtermColors.colorTable[fgColor]), strToConvert.indexOf(ansiGroup,
264 | stringPos) - charsRemoved));
265 | }
266 | }
267 | }
268 | else if (code == 39 || code == 99)
269 | {
270 | // end foreground styles
271 | for (StyleInfo si : styles)
272 | {
273 | if (si.style instanceof ForegroundColorSpan)
274 | si.end = strToConvert.indexOf(ansiGroup, stringPos) - charsRemoved;
275 | }
276 | }
277 | else if (code == 48)
278 | {
279 | // color background
280 |
281 | if (mNumber.find() && Integer.parseInt(mNumber.group()) == 5 && mNumber.find())
282 | {
283 | int bgColor = Integer.parseInt(mNumber.group());
284 |
285 | if (bgColor < 256)
286 | {
287 | styles.add(new StyleInfo(new BackgroundColorSpan(
288 | xtermColors.colorTable[bgColor]), strToConvert.indexOf(ansiGroup,
289 | stringPos) - charsRemoved));
290 | }
291 | }
292 | }
293 | else if (code == 49 || code == 109)
294 | {
295 | // end background styles
296 | for (StyleInfo si : styles)
297 | {
298 | if (si.style instanceof BackgroundColorSpan)
299 | si.end = strToConvert.indexOf(ansiGroup, stringPos) - charsRemoved;
300 | }
301 | }
302 | else
303 | {
304 | ArrayList fakeList = new ArrayList(1);
305 | fakeList.add(code);
306 | CharacterStyle cs = getStyleFromAnsiCode(fakeList, brightOn);
307 |
308 | if (cs != null)
309 | {
310 | // create new style
311 | styles.add(new StyleInfo(cs, strToConvert.indexOf(ansiGroup, stringPos)
312 | - charsRemoved));
313 |
314 | }
315 | else
316 | {
317 | Log.w(TAG, "Unknown ANSI code: " + code);
318 | }
319 | }
320 | }
321 | catch (NumberFormatException ex)
322 | {
323 | Log.w(TAG, "Not a valid ANSI number: " + mNumber.group());
324 | }
325 | }
326 |
327 | if (codesFound == 0)
328 | {
329 | // end all active styles
330 | for (StyleInfo si : styles)
331 | {
332 | if (si.end == -1)
333 | si.end = strToConvert.indexOf(ansiGroup, stringPos) - charsRemoved;
334 | }
335 | brightOn = false;
336 | }
337 |
338 | stringPos = strToConvert.indexOf(ansiGroup, stringPos) + ansiGroup.length();
339 | charsRemoved += ansiGroup.length();
340 | }
341 |
342 | // adjust locations of spans if they weren't ended and add spans to
343 | // spannable
344 | for (StyleInfo si : styles)
345 | {
346 | if (si.end == -1)
347 | si.end = strippedText.length() - 1;
348 |
349 | if (si.start >= 0 && si.start < si.end && si.end >= 1 && si.end < strippedText.length())
350 | ansiString.setSpan(si.style, si.start, si.end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
351 | else
352 | Log.w(TAG, "Bad ANSI span: start: '" + si.start + "' end: '" + si.end + "'");
353 | }
354 |
355 | returnText = ansiString;
356 | }
357 | else
358 | returnText = strippedText;
359 |
360 | return returnText;
361 | }
362 |
363 | public static CharacterStyle getStyleFromAnsiCode(ArrayList ansiCode, boolean brightOn)
364 | {
365 | CharacterStyle returnStyle = null;
366 | int len = ansiCode.size();
367 |
368 | if (len == 1)
369 | {
370 | int color = ansiCode.get(0);
371 |
372 | if (brightOn && ((color >= 30 && color < 38) || (color >= 40 && color < 48)))
373 | color += 60;
374 |
375 | switch (color)
376 | {
377 | // text style
378 | case 3: // italics
379 | returnStyle = new StyleSpan(android.graphics.Typeface.ITALIC);
380 | break;
381 | case 4: // underscore
382 | returnStyle = new UnderlineSpan();
383 | break;
384 | case 9: // strikethrough
385 | returnStyle = new StrikethroughSpan();
386 | break;
387 |
388 | // text colors
389 | case 30: // black
390 | returnStyle = new ForegroundColorSpan(BLACK);
391 | break;
392 | case 31: // red
393 | returnStyle = new ForegroundColorSpan(RED);
394 | break;
395 | case 32: // green
396 | returnStyle = new ForegroundColorSpan(GREEN);
397 | break;
398 | case 33: // yellow
399 | returnStyle = new ForegroundColorSpan(YELLOW);
400 | break;
401 | case 34: // blue
402 | returnStyle = new ForegroundColorSpan(BLUE);
403 | break;
404 | case 35: // magenta
405 | returnStyle = new ForegroundColorSpan(MAGENTA);
406 | break;
407 | case 36: // cyan
408 | returnStyle = new ForegroundColorSpan(CYAN);
409 | break;
410 | case 37: // white
411 | returnStyle = new ForegroundColorSpan(GRAY);
412 | break;
413 |
414 | // bright text colors
415 | case 90: // black
416 | returnStyle = new ForegroundColorSpan(DARK_GRAY);
417 | break;
418 | case 91: // red
419 | returnStyle = new ForegroundColorSpan(BRIGHT_RED);
420 | break;
421 | case 92: // green
422 | returnStyle = new ForegroundColorSpan(BRIGHT_GREEN);
423 | break;
424 | case 93: // yellow
425 | returnStyle = new ForegroundColorSpan(BRIGHT_YELLOW);
426 | break;
427 | case 94: // blue
428 | returnStyle = new ForegroundColorSpan(BRIGHT_BLUE);
429 | break;
430 | case 95: // magenta
431 | returnStyle = new ForegroundColorSpan(BRIGHT_MAGENTA);
432 | break;
433 | case 96: // cyan
434 | returnStyle = new ForegroundColorSpan(BRIGHT_CYAN);
435 | break;
436 | case 97: // white
437 | returnStyle = new ForegroundColorSpan(WHITE);
438 | break;
439 |
440 | // bg colors
441 | case 40: // black
442 | returnStyle = new BackgroundColorSpan(BLACK);
443 | break;
444 | case 41: // red
445 | returnStyle = new BackgroundColorSpan(RED);
446 | break;
447 | case 42: // green
448 | returnStyle = new BackgroundColorSpan(GREEN);
449 | break;
450 | case 43: // yellow
451 | returnStyle = new BackgroundColorSpan(YELLOW);
452 | break;
453 | case 44: // blue
454 | returnStyle = new BackgroundColorSpan(BLUE);
455 | break;
456 | case 45: // magenta
457 | returnStyle = new BackgroundColorSpan(MAGENTA);
458 | break;
459 | case 46: // cyan
460 | returnStyle = new BackgroundColorSpan(CYAN);
461 | break;
462 | case 47: // white
463 | returnStyle = new BackgroundColorSpan(GRAY);
464 | break;
465 |
466 | // bright bg colors
467 | case 100: // black
468 | returnStyle = new BackgroundColorSpan(DARK_GRAY);
469 | break;
470 | case 101: // red
471 | returnStyle = new BackgroundColorSpan(BRIGHT_RED);
472 | break;
473 | case 102: // green
474 | returnStyle = new BackgroundColorSpan(BRIGHT_GREEN);
475 | break;
476 | case 103: // yellow
477 | returnStyle = new BackgroundColorSpan(BRIGHT_YELLOW);
478 | break;
479 | case 104: // blue
480 | returnStyle = new BackgroundColorSpan(BRIGHT_BLUE);
481 | break;
482 | case 105: // magenta
483 | returnStyle = new BackgroundColorSpan(BRIGHT_MAGENTA);
484 | break;
485 | case 106: // cyan
486 | returnStyle = new BackgroundColorSpan(BRIGHT_CYAN);
487 | break;
488 | case 107: // white
489 | returnStyle = new BackgroundColorSpan(WHITE);
490 | break;
491 | }
492 | }
493 | else if (len == 3 && ansiCode.get(1) == 5)
494 | {
495 | int idxZero = ansiCode.get(0);
496 | int idxTwo = ansiCode.get(2);
497 |
498 | if (idxZero == 38)
499 | {
500 | returnStyle = new ForegroundColorSpan(idxTwo);
501 | }
502 | else if (idxZero == 48)
503 | {
504 | returnStyle = new BackgroundColorSpan(idxTwo);
505 | }
506 | }
507 |
508 | return returnStyle;
509 | }
510 | }
511 |
--------------------------------------------------------------------------------
/MuklukMudClient/src/main/java/com/crap/mukluk/WorldListActivity.java:
--------------------------------------------------------------------------------
1 | package com.crap.mukluk;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.io.ObjectInputStream;
9 | import java.io.ObjectOutputStream;
10 | import java.util.ArrayList;
11 | import android.app.AlertDialog;
12 | import android.app.ListActivity;
13 | import android.content.Context;
14 | import android.content.DialogInterface;
15 | import android.content.Intent;
16 | import android.content.SharedPreferences;
17 | import android.os.Bundle;
18 | import android.os.Environment;
19 | import android.preference.PreferenceManager;
20 | import android.util.Log;
21 | import android.view.ContextMenu;
22 | import android.view.KeyEvent;
23 | import android.view.LayoutInflater;
24 | import android.view.Menu;
25 | import android.view.MenuInflater;
26 | import android.view.MenuItem;
27 | import android.view.View;
28 | import android.view.ViewGroup;
29 | import android.view.ContextMenu.ContextMenuInfo;
30 | import android.widget.AdapterView;
31 | import android.widget.EditText;
32 | import android.widget.ListView;
33 | import android.widget.TextView;
34 | import android.widget.Toast;
35 | import android.widget.AdapterView.AdapterContextMenuInfo;
36 | import android.widget.AdapterView.OnItemClickListener;
37 |
38 | // Initial activity that displays the list of defined worlds
39 | public class WorldListActivity extends ListActivity
40 | {
41 | private static final String TAG = "WordListActivity";
42 |
43 | private Context _context;
44 | private WorldDbAdapter _worldDbAdapter;
45 | private ListView _listView;
46 | private int _worldToDeleteID = -1;
47 | private AlertDialog _alertDialog = null;
48 |
49 | @Override
50 | public void onCreate(Bundle savedInstanceState)
51 | {
52 | super.onCreate(savedInstanceState);
53 | setContentView(R.layout.world_list);
54 |
55 | _context = getApplicationContext();
56 |
57 | _worldDbAdapter = new WorldDbAdapter(_context);
58 | _worldDbAdapter.open();
59 |
60 | _listView = getListView();
61 | registerForContextMenu(_listView);
62 |
63 | _listView.setOnItemClickListener(
64 | new OnItemClickListener()
65 | {
66 | @Override
67 | public void onItemClick(AdapterView> arg0, View view, int position, long id)
68 | {
69 | World world = _worldDbAdapter.getWorld((int) id);
70 |
71 | if (world.host.trim().length() == 0 || world.host.trim().length() == 0)
72 | Toast.makeText(_context, _context.getString(R.string.toast_world_host_or_port_not_set), Toast.LENGTH_SHORT).show();
73 | else
74 | startWorldConnection(world);
75 | }
76 | });
77 | }
78 |
79 | @Override
80 | public void onResume()
81 | {
82 | super.onResume();
83 | fillWorldList();
84 |
85 | if (_listView.getCount() == 0)
86 | showAddConfirmationDialog();
87 |
88 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(_context);
89 | }
90 |
91 | @Override
92 | public void onPause()
93 | {
94 | super.onPause();
95 |
96 | if (_alertDialog != null)
97 | _alertDialog.dismiss();
98 | }
99 |
100 | @Override
101 | public void onDestroy()
102 | {
103 | super.onDestroy();
104 |
105 | _worldDbAdapter.close();
106 | _worldDbAdapter = null;
107 | }
108 |
109 | @Override
110 | public boolean onCreateOptionsMenu(Menu menu)
111 | {
112 | MenuInflater inflater = getMenuInflater();
113 | inflater.inflate(R.menu.world_list_menu, menu);
114 | return true;
115 | }
116 |
117 | @Override
118 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
119 | {
120 | super.onCreateContextMenu(menu, v, menuInfo);
121 | MenuInflater inflater = getMenuInflater();
122 | inflater.inflate(R.menu.world_list_context_menu, menu);
123 | }
124 |
125 | @Override
126 | public boolean onOptionsItemSelected(MenuItem item)
127 | {
128 | switch (item.getItemId())
129 | {
130 | case R.id.menu_item_new_world:
131 | startAddWorldActivity();
132 | return true;
133 | case R.id.menu_item_global_settings:
134 | startGlobalSettingsActivity();
135 | return true;
136 | case R.id.menu_item_export_worlds:
137 | exportWorlds();
138 | return true;
139 | case R.id.menu_item_import_worlds:
140 | importWorlds();
141 | return true;
142 | case R.id.menu_item_about:
143 | startAbout();
144 | return true;
145 | default:
146 | return super.onOptionsItemSelected(item);
147 | }
148 | }
149 |
150 | @Override
151 | public boolean onContextItemSelected(MenuItem item)
152 | {
153 | AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
154 |
155 | switch (item.getItemId())
156 | {
157 | case R.id.menu_item_edit_world :
158 | startEditWorldActivity(_worldDbAdapter.getWorld((int) info.id));
159 | return true;
160 | case R.id.menu_item_copy_world :
161 | World worldToCopy = _worldDbAdapter.getWorld((int) info.id);
162 | worldToCopy.name += " (Copy)";
163 | _worldDbAdapter.addWorldToDatabase(worldToCopy); // id is ignored so this is safe
164 | fillWorldList();
165 | return true;
166 | case R.id.menu_item_clear_world_cache :
167 | showCacheClearConfirmationDialog((int) info.id);
168 | return true;
169 | case R.id.menu_item_delete_world :
170 | showDeleteConfirmationDialog((int) info.id);
171 | return true;
172 | default:
173 | return super.onContextItemSelected(item);
174 | }
175 | }
176 |
177 | @Override
178 | // called when a sub-activity returns
179 | public void onActivityResult(int requestCode, int resultCode, Intent data)
180 | {
181 | if (resultCode == RESULT_OK)
182 | {
183 | World worldReturned;
184 |
185 | switch (requestCode)
186 | {
187 | case AddEditWorldActivity.ADD_WORLD :
188 | worldReturned = (World) data.getExtras().getParcelable("world");
189 | _worldDbAdapter.addWorldToDatabase(worldReturned);
190 | Toast.makeText(_context, _context.getString(R.string.toast_changes_saved), Toast.LENGTH_SHORT).show();
191 | break;
192 | case AddEditWorldActivity.EDIT_WORLD :
193 | worldReturned = (World) data.getExtras().getParcelable("world");
194 | _worldDbAdapter.updateWorldInDatabase(worldReturned);
195 | Toast.makeText(_context, _context.getString(R.string.toast_changes_saved), Toast.LENGTH_SHORT).show();
196 | break;
197 | }
198 | }
199 | }
200 |
201 | @Override
202 | // intercept back button
203 | public boolean onKeyDown(int keyCode, KeyEvent event)
204 | {
205 | if (keyCode == KeyEvent.KEYCODE_BACK && ((WorldListAdapter) getListAdapter()).getConnectedWorlds() > 0)
206 | {
207 | showBackButtonDialog();
208 | return false;
209 | }
210 |
211 | return super.onKeyDown(keyCode, event);
212 | }
213 |
214 | private void fillWorldList()
215 | {
216 | setListAdapter(new WorldListAdapter(getApplicationContext(), _worldDbAdapter.getAllWorlds()));
217 | }
218 |
219 | private void exportWorlds()
220 | {
221 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
222 | {
223 | final World[] worlds = _worldDbAdapter.getAllWorlds();
224 |
225 | if (worlds != null && worlds.length > 0)
226 | {
227 | _alertDialog = new AlertDialog.Builder(this).create();
228 | LayoutInflater inflater = (LayoutInflater) _context.getSystemService(LAYOUT_INFLATER_SERVICE);
229 | View layout = inflater.inflate(R.layout.text_dialog, (ViewGroup) findViewById(R.id.layout_text_dialog_root));
230 | _alertDialog.setView(layout);
231 |
232 | _alertDialog.setTitle(getString(R.string.dialog_title_export_worlds));
233 | ((TextView) layout.findViewById(R.id.label_value)).setText(getString(R.string.dialog_message_export_worlds));
234 |
235 | final EditText textInput = (EditText) layout.findViewById(R.id.text_value);
236 | textInput.setText("/mukluk/mukluk.worlds");
237 |
238 | _alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.button_okay), new DialogInterface.OnClickListener()
239 | {
240 | @Override
241 | public void onClick(DialogInterface dialog, int which)
242 | {
243 | String enteredFile = textInput.getText().toString();
244 | File exportFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + enteredFile);
245 |
246 | if (exportFile.exists())
247 | exportFile.delete();
248 |
249 | if (!exportFile.getParentFile().exists())
250 | exportFile.getParentFile().mkdirs();
251 |
252 | ArrayList serWorlds = new ArrayList();
253 |
254 | for (World w : worlds)
255 | serWorlds.add(new SerializableWorld(w));
256 |
257 | try
258 | {
259 | ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(exportFile));
260 | out.writeObject(serWorlds);
261 | out.close();
262 |
263 | Toast.makeText(getApplicationContext(), getString(R.string.toast_export_success, exportFile.getAbsolutePath()), Toast.LENGTH_LONG).show();
264 | }
265 | catch (FileNotFoundException ex)
266 | {
267 | Log.e(TAG, ex.toString());
268 | Toast.makeText(getApplicationContext(), getString(R.string.toast_export_failure), Toast.LENGTH_LONG).show();
269 | }
270 | catch (IOException ex)
271 | {
272 | Log.e(TAG, ex.toString());
273 | Toast.makeText(getApplicationContext(), getString(R.string.toast_export_failure), Toast.LENGTH_LONG).show();
274 | }
275 | }
276 | });
277 |
278 | _alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.button_cancel), new DialogInterface.OnClickListener()
279 | {
280 | @Override
281 | public void onClick(DialogInterface dialog, int which) {}
282 | });
283 |
284 | _alertDialog.show();
285 | }
286 | else
287 | {
288 | Toast.makeText(getApplicationContext(), getString(R.string.toast_export_no_worlds), Toast.LENGTH_LONG).show();
289 | }
290 | }
291 | else
292 | {
293 | Toast.makeText(getApplicationContext(), getString(R.string.toast_export_failure), Toast.LENGTH_LONG).show();
294 | }
295 | }
296 |
297 | private void importWorlds()
298 | {
299 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
300 | {
301 | _alertDialog = new AlertDialog.Builder(this).create();
302 | LayoutInflater inflater = (LayoutInflater) _context.getSystemService(LAYOUT_INFLATER_SERVICE);
303 | View layout = inflater.inflate(R.layout.text_dialog, (ViewGroup) findViewById(R.id.layout_text_dialog_root));
304 | _alertDialog.setView(layout);
305 |
306 | _alertDialog.setTitle(getString(R.string.dialog_title_import_worlds));
307 | ((TextView) layout.findViewById(R.id.label_value)).setText(getString(R.string.dialog_message_import_worlds));
308 |
309 | final EditText textInput = (EditText) layout.findViewById(R.id.text_value);
310 | textInput.setText("/mukluk/mukluk.worlds");
311 |
312 | _alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.button_okay), new DialogInterface.OnClickListener()
313 | {
314 | @SuppressWarnings("unchecked")
315 | @Override
316 | public void onClick(DialogInterface dialog, int which)
317 | {
318 | File initialPath = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
319 | String enteredFile = textInput.getText().toString();
320 | File importFile = new File(initialPath.getAbsolutePath() + enteredFile);
321 | ObjectInputStream in = null;
322 |
323 | if (importFile.exists())
324 | {
325 | try
326 | {
327 | ArrayList worlds;
328 | in = new ObjectInputStream(new FileInputStream(importFile));
329 |
330 | try
331 | {
332 | worlds = (ArrayList) in.readObject();
333 |
334 | for (SerializableWorld w : worlds)
335 | _worldDbAdapter.addWorldToDatabase(w.getAsWorld());
336 |
337 | fillWorldList();
338 | }
339 | catch (ClassNotFoundException ex)
340 | {
341 | // this shouldn't happen
342 | Log.e(TAG, ex.toString());
343 | }
344 | }
345 | catch (IOException ex)
346 | {
347 | Toast.makeText(getApplicationContext(), getString(R.string.toast_import_failure), Toast.LENGTH_LONG).show();
348 | }
349 | }
350 | else
351 | {
352 | Toast.makeText(getApplicationContext(), getString(R.string.toast_import_invalid_file, importFile.getAbsoluteFile()), Toast.LENGTH_LONG).show();
353 | }
354 | }
355 | });
356 |
357 | _alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.button_cancel), new DialogInterface.OnClickListener()
358 | {
359 | @Override
360 | public void onClick(DialogInterface dialog, int which) {}
361 | });
362 |
363 | _alertDialog.show();
364 | }
365 | else
366 | {
367 | Toast.makeText(getApplicationContext(), getString(R.string.toast_import_failure), Toast.LENGTH_LONG).show();
368 | }
369 | }
370 |
371 | private void startAbout()
372 | {
373 | Intent intent = new Intent(this, AboutActivity.class);
374 | startActivity(intent);
375 | }
376 |
377 | private void startAddWorldActivity()
378 | {
379 | Intent intent = new Intent(this, AddEditWorldActivity.class);
380 | startActivityForResult(intent, AddEditWorldActivity.ADD_WORLD);
381 | }
382 |
383 | private void startEditWorldActivity(World world)
384 | {
385 | Intent intent = new Intent(this, AddEditWorldActivity.class);
386 | intent.putExtra("world", world);
387 | startActivityForResult(intent, AddEditWorldActivity.EDIT_WORLD);
388 | }
389 |
390 | private void startGlobalSettingsActivity()
391 | {
392 | Intent intent = new Intent(this, GlobalSettingsActivity.class);
393 | startActivity(intent);
394 | }
395 |
396 | private void startWorldConnection(World world)
397 | {
398 | Intent intent = new Intent(this, WorldConnectionActivity.class);
399 | intent.putExtra("world", world);
400 | intent.putExtra("createdFromWorldList", true);
401 | startActivity(intent);
402 | }
403 |
404 | private void showBackButtonDialog()
405 | {
406 | _alertDialog = new AlertDialog.Builder(this).create();
407 | _alertDialog.setTitle(_context.getString(R.string.dialog_title_back));
408 | _alertDialog.setMessage(_context.getString(R.string.dialog_message_back));
409 | _alertDialog.setButton(_context.getString(R.string.dialog_button_back_disconnect),
410 | new DialogInterface.OnClickListener()
411 | {
412 | public void onClick(DialogInterface dialog, int which)
413 | {
414 | Intent intent = new Intent(getApplicationContext(), WorldConnectionService.class);
415 | stopService(intent);
416 | finish();
417 | }
418 | });
419 | _alertDialog.setButton2(_context.getString(R.string.button_cancel),
420 | new DialogInterface.OnClickListener()
421 | {
422 | public void onClick(DialogInterface dialog, int which) {}
423 | });
424 | _alertDialog.setButton3(_context.getString(R.string.dialog_button_back_stay_connected),
425 | new DialogInterface.OnClickListener()
426 | {
427 | public void onClick(DialogInterface dialog, int which)
428 | {
429 | finish();
430 | }
431 | });
432 | _alertDialog.show();
433 | }
434 |
435 | private void showAddConfirmationDialog()
436 | {
437 | _alertDialog = new AlertDialog.Builder(this).create();
438 | _alertDialog.setTitle(_context.getString(R.string.dialog_title_no_worlds));
439 | _alertDialog.setMessage(_context.getString(R.string.dialog_message_no_worlds));
440 | _alertDialog.setButton(_context.getString(R.string.button_okay),
441 | new DialogInterface.OnClickListener()
442 | {
443 | public void onClick(DialogInterface dialog, int which)
444 | {
445 | startAddWorldActivity();
446 | }
447 | });
448 | _alertDialog.setButton2(_context.getString(R.string.button_cancel),
449 | new DialogInterface.OnClickListener()
450 | {
451 | public void onClick(DialogInterface dialog, int which)
452 | {
453 | return;
454 | }
455 | });
456 | _alertDialog.show();
457 | }
458 |
459 | private void showCacheClearConfirmationDialog(int worldID)
460 | {
461 | final World world = _worldDbAdapter.getWorld(worldID);
462 | final String worldName = world.name.trim().length() == 0 ? "[Unnamed World]" : world.name;
463 | _alertDialog = new AlertDialog.Builder(this).create();
464 | _alertDialog.setTitle(String.format(_context.getString(R.string.dialog_title_cache), worldName));
465 | _alertDialog.setMessage(_context.getString(R.string.dialog_message_cache));
466 | _alertDialog.setButton(_context.getString(R.string.button_okay),
467 | new DialogInterface.OnClickListener()
468 | {
469 | public void onClick(DialogInterface dialog, int which)
470 | {
471 | deleteFile(world.getCommandHistoryCacheFileName());
472 | deleteFile(world.getConsoleCacheFileName());
473 | deleteFile(world.getConsoleStyleCacheJsonFileName());
474 | deleteFile(world.getConsoleStyleCacheJacksonJsonFileName());
475 | deleteFile(world.getURLCacheFileName());
476 | Toast.makeText(_context, String.format(getString(R.string.toast_cache_cleared), worldName), Toast.LENGTH_LONG).show();
477 | }
478 | });
479 | _alertDialog.setButton2(_context.getString(R.string.button_cancel),
480 | new DialogInterface.OnClickListener()
481 | {
482 | public void onClick(DialogInterface dialog, int which)
483 | {
484 | return;
485 | }
486 | });
487 | _alertDialog.show();
488 | }
489 |
490 | private void showDeleteConfirmationDialog(int worldID)
491 | {
492 | _worldToDeleteID = worldID;
493 |
494 | World world = _worldDbAdapter.getWorld(worldID);
495 | _alertDialog = new AlertDialog.Builder(this).create();
496 | _alertDialog.setTitle(world.name.trim().length() == 0 ? "[Unnamed World]" : world.name);
497 | _alertDialog.setMessage(_context.getString(R.string.dialog_message_delete_world_confirmation));
498 | _alertDialog.setButton(_context.getString(R.string.button_okay),
499 | new DialogInterface.OnClickListener()
500 | {
501 | public void onClick(DialogInterface dialog, int which)
502 | {
503 | int currentStatus = WorldConnectionService.getWorldConnectionStatus(_worldToDeleteID);
504 |
505 | if (currentStatus == WorldConnectionService.STATUS_CONNECTING || currentStatus == WorldConnectionService.STATUS_CONNECTED)
506 | {
507 | Toast.makeText(_context, getString(R.string.toast_deleted_connected_world), Toast.LENGTH_LONG).show();
508 | }
509 | else
510 | {
511 | World worldBeingDeleted = _worldDbAdapter.getWorld(_worldToDeleteID);
512 |
513 | deleteFile(worldBeingDeleted.getConsoleCacheFileName());
514 | deleteFile(worldBeingDeleted.getCommandHistoryCacheFileName());
515 | deleteFile(worldBeingDeleted.getURLCacheFileName());
516 | deleteFile(worldBeingDeleted.getConsoleStyleCacheJsonFileName());
517 | deleteFile(worldBeingDeleted.getConsoleStyleCacheJacksonJsonFileName());
518 | _worldDbAdapter.deleteWorldFromDatabase(_worldToDeleteID);
519 |
520 | _worldToDeleteID = -1;
521 | fillWorldList();
522 | }
523 | }
524 | });
525 | _alertDialog.setButton2(_context.getString(R.string.button_cancel),
526 | new DialogInterface.OnClickListener()
527 | {
528 | public void onClick(DialogInterface dialog, int which)
529 | {
530 | _worldToDeleteID = -1;
531 | return;
532 | }
533 | });
534 | _alertDialog.show();
535 | }
536 | }
--------------------------------------------------------------------------------