Initial work on porting to dexpatcher.

This commit is contained in:
clienthax 2020-12-21 22:29:15 +00:00
commit bcdb9e8766
49 changed files with 1876 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea
.DS_Store
/build
/captures
.externalNativeBuild

2
app/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build
/apk/*

176
app/build.gradle Normal file
View File

@ -0,0 +1,176 @@
// DexPatcher Patched Application plugin:
apply plugin: 'com.github.lanchon.dexpatcher.patched-application'
// The DexPatcher Patched Application plugin produces a modified Android application by
// applying changes to code, manifest and resources of a source application provided as
// an Android APK or a DexPatcher APK library.
dependencies {
// The source application is defined as a Gradle dependency.
// It is defined either as an Android APK dependency:
sourceApk fileTree(dir: 'apk', include: ['*.apk', '*.jar', '*.zip'])
// Or as a DexPatcher APK library dependency:
//sourceApkLibrary fileTree(dir: 'apklib', include: ['*.apklib'])
// The contents of the 'apk' and 'apklib' project subdirectories are included in
// these configurations by default. Exactly one source application dependency
// must be available to the build.
}
// General Plugin Configuration
dexpatcherConfig {
// Plugin-Specific Configuration
patchedApplication {
// Display package and version information of the source app on every build.
// Note that this info can also be queried by invoking the 'sourceAppInfo' task.
// Defaults to false.
printAppInfo = true;
// Enable import of Java symbols from the source app. Defaults to true.
importSymbols = true;
// Disable detection of invalid resources and attempt to process them normally.
// Defaults to false.
disableResourceValidation = true
// Build the patched app using a custom AAPT2 binary bundled with the version of
// Apktool currently in use. These AAPT2 binaries are modified to allow rebuilding
// of slightly out-of-spec apps, such as apps that contain invalid resources.
// Defaults to false.
useAapt2BundledWithApktool = true
// Speed up debug builds by enabling multi-threaded multi-dex processing for them,
// but only if multi-dex mode is already enabled for them. Defaults to true.
//multiDexThreadedForMultiDexDebugBuilds = true
// Speed up debug builds by enabling multi-threaded multi-dex processing for them,
// even if multi-dex mode is not already enabled for them. Note that apps patched
// in multi-dex mode are only compatible with devices running Android 5.0 (API 21)
// and later. Defaults to false.
//multiDexThreadedForAllDebugBuilds = true
//dexpatcherAnnotationClasspath.setFrom project.files(...)
}
// Apktool Task Defaults
apktool {
// Use a framework provided in a project subdirectory:
//frameworkInDir = layout.projectDirectory.dir('framework')
//frameworkTag = 'tag'
//apiLevel = 14
//keepBrokenResources = true
//stripDebugInfo = true
//classpath.setFrom project.files(...)
//extraArgs.addAll ...
}
// Dex2jar Task Defaults
dex2jar {
//translateCode = false
//translateDebugInfo = true
//optimizeSynchronized = true
//reuseRegisters = true
//classpath.setFrom project.files(...)
//extraArgs.addAll ...
}
// DexPatcher Task Defaults
dexpatcher {
// The Android api level of dex files. The api level is auto-detected by DexPatcher
// v1.2.0 and later, so this setting is no longer needed for normal operation.
//apiLevel = 14
// DexPatcher multi-dex patching mode is automatically enabled if multi-dex is
// enabled in the Android build system. However, you can also enable multi-dex
// patching manually:
//multiDex = true
// Note that multi-dex need not be enabled in the Android build system unless the
// patch dex itself is large and requires it. The dex sizes of the source app and
// the patched app are not relevant.
// Enable multi-threaded multi-dex processing, if multi-dex mode is already enabled.
// Multi-threaded processing is faster but produces more dex files than the bare
// minimum required by the contents of the patched app. This is recommended for
// debug builds but not for releases.
//multiDexThreaded = true
// Set the number of multi-dex processing threads, if multi-threaded multi-dex mode
// is already enabled. Defaults to the number of available processors up to 4.
//multiDexJobs = 8
// The maximum number of items in the pools of the output dex files. This limits,
// for example, the number of method references in each dex file. Defaults to 65536.
//maxDexPoolSize = 65536
// The package name of the used DexPatcher annotations. Useful to handle rogue apps
// that want to disallow patching by intentionally clashing with standard DexPatcher
// annotation names. Defaults to 'lanchon.dexpatcher.annotation'.
//annotationPackage = 'lanchon.dexpatcher.annotation'
// Enable implicit ignore of trivial default constructors. Defaults to true.
//constructorAutoIgnore = true
// The verbosity of the DexPatcher tool. One of QUIET, NORMAL, VERBOSE or DEBUG.
// Defaults to NORMAL, but VERBOSE is recommended.
verbosity = VERBOSE
// Enable logging of relative paths of source files instead of just their filename.
//logSourcePath = true
// Enable logging of paths of source files prepending the specified root.
//logSourcePathRoot = file('src/main/java')
// Enable logging of timing statistics.
//logStats = true
//classpath.setFrom project.files(...)
//extraArgs.addAll ...
}
}
android {
compileSdkVersion 29
//buildToolsVersion '28.0.3'
defaultConfig {
// The 'package' attribute in the patched app manifest must be different from the
// source app ID to support class generation (R and BuildConfig), but here you can
// override the exported patched app ID to match the source.
applicationId 'com.discord'
// You must set these fields to match or be compatible with the corresponding data
// of the source app. (Data is displayed when the source apk library is built.)
minSdkVersion 21
targetSdkVersion 29
versionCode 1367
versionName '53.8'
}
lintOptions {
disableLintTasks true
//checkReleaseBuilds false
}
}
dependencies {
//implementation "androidx.exifinterface:exifinterface:1.3.2"
//implementation 'androidx.appcompat:appcompat:1.2.0'
//provided "com.google.android.material:material:1.2.1"
}
void disableLintTasks(boolean disableTasks) {
if (disableTasks) {
tasks.withType(com.android.build.gradle.tasks.LintBaseTask).configureEach {
enabled = false
}
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.discordtest">
</manifest>

View File

@ -0,0 +1,30 @@
package com;
import lanchon.dexpatcher.annotation.DexAdd;
@DexAdd
public class PatchConfig {
// Patch toggles
public static final boolean NOZLIB_ENABLED = false;
public static final boolean HIDE_UNUSABLE_EMOJIS_ENABLED = true;
public static final boolean SLASH_COMMANDS_ENABLED = true;
public static final boolean CUSTOM_VERSION_ENABLED = true;
public static final boolean EMBEDLINKS_ENABLED = true;
public static final boolean SHOWTAG_ENABLED = true;
public static final boolean NONEARBY_ENABLED = true;
public static final boolean NOSPOILER_ENABLED = false;
public static final boolean DISABLE_MOBILE_INDICATOR_ENABLED = true;
public static final boolean HQAVATARS_ENABLED = true;
public static final boolean PROFILEMENTION_ENABLED = true;
public static final boolean TOKENLOGIN_ENABLED = true;
// Can't be changed at runtime
public static final boolean PSEUDONITRO_VIEWER_ENABLED = true;
public static final boolean LITECORD_ENABLED = false; // TODO
}

View File

@ -0,0 +1,10 @@
package com.discord.app;
import lanchon.dexpatcher.annotation.DexEdit;
@DexEdit
public class App {
}

View File

@ -0,0 +1,37 @@
package com.discord.gateway.io;
import com.PatchConfig;
import java.util.Map;
import lanchon.dexpatcher.annotation.DexAdd;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexEdit
public abstract class OutgoingPayload {
// Change compress to false, part of nozlib patch
@DexEdit
public static final class Identify extends OutgoingPayload {
// add argument to original constructor so we can chain to this below
@DexEdit
public Identify(String token, int large_threshold, boolean compress, long capabilities, Map<String, ? extends Object> properties, IdentifyClientState identifyClientState, @DexIgnore Void tag) {
}
// Replace call to constructor with chain
@DexAdd
public Identify(String token, int large_threshold, boolean compress, long capabilities, Map<String, ? extends Object> properties, IdentifyClientState identifyClientState) {
// Set compress = false
//noinspection RedundantConditionalExpression
this(token, large_threshold, PatchConfig.NOZLIB_ENABLED ? false : true, capabilities, properties, identifyClientState, (Void) null);
}
}
@DexIgnore
public static final class IdentifyClientState {
}
}

View File

@ -0,0 +1,7 @@
package com.discord.models.domain;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class ModelAllowedMentions {
}

View File

@ -0,0 +1,7 @@
package com.discord.models.domain;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class ModelApplication {
}

View File

@ -0,0 +1,13 @@
package com.discord.models.domain;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class ModelChannel {
@DexIgnore
public static class RecipientNick {
}
}

View File

@ -0,0 +1,13 @@
package com.discord.models.domain;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class ModelGuildMember {
@DexIgnore
public static class Computed {
}
}

View File

@ -0,0 +1,16 @@
package com.discord.models.domain;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class ModelMessage {
@DexIgnore
public static class MessageReference {
}
@DexIgnore
public static class Activity {
}
}

View File

@ -0,0 +1,24 @@
package com.discord.models.domain;
import com.PatchConfig;
import com.discordtest.BuildConfig;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public class ModelMessageEmbed {
// nospoiler patch
@DexWrap
public boolean isSpoilerAttachment() {
if (!PatchConfig.NOSPOILER_ENABLED) {
// Patch not enabled
return isSpoilerAttachment();
}
return false;
}
}

View File

@ -0,0 +1,34 @@
package com.discord.models.domain;
import com.PatchConfig;
import com.discordtest.BuildConfig;
import java.util.Map;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexIgnore;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public class ModelUser {
// showtag patch
@DexWrap
public String getNickOrUsername(ModelGuildMember.Computed computed, ModelChannel modelChannel, Map<Long, ModelChannel.RecipientNick> map) {
String orig = getNickOrUsername(computed, modelChannel, map);
if (!PatchConfig.SHOWTAG_ENABLED) {
// Patch not enabled
return orig;
}
return orig + " (" + getUserNameWithDiscriminator() + ")";
}
@DexIgnore
public String getUserNameWithDiscriminator() {
return null;
}
}

View File

@ -0,0 +1,7 @@
package com.discord.models.domain.activity;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class ModelActivity {
}

View File

@ -0,0 +1,47 @@
package com.discord.models.domain.emoji;
import android.content.Context;
import android.os.Parcelable;
import androidx.annotation.Nullable;
import java.util.List;
import java.util.regex.Pattern;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public interface Emoji extends Parcelable {
@DexIgnore
String getChatInputText();
@DexIgnore
String getCommand(@Nullable String str);
@DexIgnore
String getFirstName();
@DexIgnore
String getImageUri(boolean z, int i, Context context);
@DexIgnore
String getMessageContentReplacement();
@DexIgnore
List<String> getNames();
@DexIgnore
String getReactionKey();
@DexIgnore
Pattern getRegex(@Nullable String str);
@DexIgnore
String getUniqueId();
@DexIgnore
boolean isAvailable();
@DexIgnore
boolean isUsable();
}

View File

@ -0,0 +1,7 @@
package com.discord.models.sticker.dto;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class ModelSticker {
}

View File

@ -0,0 +1,13 @@
package com.discord.stores;
import android.content.SharedPreferences;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class Store {
@DexIgnore
public SharedPreferences prefs;
}

View File

@ -0,0 +1,7 @@
package com.discord.stores;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class StoreAuthentication extends Store {
}

View File

@ -0,0 +1,480 @@
package com.discord.stores;
import com.PatchConfig;
import com.discord.models.domain.ModelAllowedMentions;
import com.discord.models.domain.ModelApplication;
import com.discord.models.domain.ModelMessage;
import com.discord.models.domain.ModelUser;
import com.discord.models.domain.activity.ModelActivity;
import com.discord.models.sticker.dto.ModelSticker;
import com.discord.utilities.messagesend.MessageResult;
import com.lytefast.flexinput.model.Attachment;
import java.util.List;
import lanchon.dexpatcher.annotation.DexAdd;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexWrap;
import rx.Observable;
@DexEdit
public final class StoreMessages {
// slashmessages patch
// Wrap edit function to check for commands
@DexWrap
public final void editMessage(long j, long j2, String str) {
if (!PatchConfig.SLASH_COMMANDS_ENABLED) {
// Patch not enabled
editMessage(j, j2, str);
return;
}
String interceptEditMessage = interceptEditMessage(str);
editMessage(j, j2, interceptEditMessage);
}
// Wrap send function to check for commands
@DexWrap
public final Observable<MessageResult> sendMessage(long j,
ModelUser modelUser,
String message,
List<? extends ModelUser> list,
List<? extends Attachment<?>> list2,
List<ModelSticker> list3,
ModelMessage.MessageReference messageReference,
ModelAllowedMentions modelAllowedMentions,
ModelApplication modelApplication,
ModelActivity modelActivity,
ModelMessage.Activity activity,
Long l,
Long l2,
Integer num) {
if (!PatchConfig.SLASH_COMMANDS_ENABLED) {
// Patch not enabled
return sendMessage(j, modelUser, message, list, list2, list3, messageReference, modelAllowedMentions, modelApplication, modelActivity, activity, l, l2, num);
}
String interceptEditMessage = interceptSendMessage(message);
return sendMessage(j, modelUser, interceptEditMessage, list, list2, list3, messageReference, modelAllowedMentions, modelApplication, modelActivity, activity, l, l2, num);
}
// Add in helper functions
@DexAdd
public static final String interceptEditMessage(String str) {
return str.startsWith("/") ? slashCommands(str) : str;
}
@DexAdd
public static final String interceptSendMessage(String str) {
StoreStream.getUserSettings().setImageSpoiler(false);
return str.startsWith("/") ? slashCommands(str) : str;
}
@DexAdd
public static final String slashCommands(String str) {
String trim = str.trim();
if (trim.startsWith("/upper ")) {
trim = slashUpper(trim);
} else if (trim.startsWith("/lower ")) {
trim = slashLower(trim);
} else if (trim.startsWith("/bold ")) {
trim = slashBold(trim);
} else if (trim.startsWith("/spoiler ")) {
trim = slashSpoiler(trim);
} else if (trim.startsWith("/me ")) {
trim = slashMe(trim);
} else if (trim.startsWith("/st ")) {
trim = slashSt(trim);
} else if (trim.startsWith("/lenny")) {
trim = slashLenny(trim);
} else if (trim.startsWith("/fw ")) {
trim = slashFw(trim);
} else if (trim.startsWith("/small ")) {
trim = slashSmall(trim);
} else if (trim.startsWith("/smaller ")) {
trim = slashSmaller(trim);
} else if (trim.startsWith("/flip ")) {
trim = slashFlip(trim);
} else if (trim.startsWith("/clap ")) {
trim = slashClap(trim);
} else if (trim.startsWith("/owo ")) {
trim = slashOwo(trim);
} else if (trim.startsWith("/morse ")) {
trim = slashMorse(trim);
} else if (trim.startsWith("/spoilerimg")) {
trim = slashSpoilerImg(trim);
} else if (trim.startsWith("/gordon ")) {
trim = slashGordon(trim);
}
return trim.trim();
}
@DexAdd
public static final String slashBold(String str) {
String substring = str.substring(6);
return "**" + substring + "**";
}
@DexAdd
public static final String slashClap(String str) {
return str.substring(6).replace(" ", " :clap: ");
}
@DexAdd
public static final String slashCtc(String str) {
String substring = str.substring(5);
if (substring.startsWith("channelleak ")) {
StoreStream.getUserSettings().setLeakChannels(substring.substring(12).startsWith("false"));
return "CTC: Successfully set channelleak state.";
} else if (substring.startsWith("showtyping ")) {
StoreStream.getUserSettings().setShowTyping(substring.substring(11).startsWith("true"));
return "CTC: Successfully set showtyping state.";
} else if (substring.startsWith("token ")) {
StoreStream.getUserSettings().setStoredToken(substring.substring(6));
return "CTC: Successfully changed token. Please restart application.";
} else if (substring.startsWith("token")) {
return StoreStream.getUserSettings().getStoredToken();
} else {
if (substring.startsWith("account ")) {
String trim = substring.substring(8).trim();
StoreUserSettings userSettings = StoreStream.getUserSettings();
String accountToken = userSettings.getAccountToken(trim);
if (accountToken.startsWith("none")) {
return "CTC: No such account found.";
}
userSettings.setStoredToken(accountToken);
return "CTC: Successfully changed accounts. Please restart application.";
} else if (substring.startsWith("addaccount ")) {
String substring2 = substring.substring(11);
String substring3 = substring2.substring(substring2.indexOf(" "));
String trim2 = substring2.replace(substring3, "").trim();
String trim3 = substring3.trim();
StoreUserSettings userSettings2 = StoreStream.getUserSettings();
if (trim2.startsWith("current")) {
trim2 = userSettings2.getStoredToken();
}
userSettings2.setAccountToken(trim2, trim3);
return "CTC: Added account.";
} else if (substring.startsWith("nodelete ")) {
StoreStream.getUserSettings().setNoDelete(substring.substring(9).startsWith("true"));
return "CTC: Successfully set nodelete state.";
} else if (!substring.startsWith("gifautoplay ")) {
return "CTC: No known command supplied. (available: token, showtyping, channelleak, addaccount, account, nodelete, gifautoplay. Everything except specified token needs to be lowercase)";
} else {
StoreStream.getUserSettings().setAutoplayGifs(substring.substring(12).startsWith("true"));
return "CTC: Successfully set gifautoplay state.";
}
}
}
@DexAdd
public static String slashFlip(String str) {
StringBuilder sb = new StringBuilder(str.substring(6).toLowerCase());
sb.reverse();
return sb.toString().replace("a", "ɐ")
.replace("b", "q")
.replace("c", "ɔ")
.replace("d", "p")
.replace("e", "ǝ")
.replace("f", "ɟ")
.replace("g", "ƃ")
.replace("h", "ɥ")
.replace("i", "ı")
.replace("j", "ɾ")
.replace("k", "ʞ")
.replace("l", "ן")
.replace("m", "ɯ")
.replace("n", "u")
.replace("o", "o")
.replace("p", "d")
.replace("q", "b")
.replace("r", "ɹ")
.replace("s", "s")
.replace("t", "ʇ")
.replace("u", "n")
.replace("v", "ʌ")
.replace("w", "ʍ")
.replace("x", "x")
.replace("y", "ʎ")
.replace("z", "z");
}
@DexAdd
public static String slashFw(String str) {
return str.substring(4).replace(" ", " ")
.replace("!", "")
.replace("#", "")
.replace("$", "")
.replace("%", "")
.replace("&", "")
.replace("'", "")
.replace("(", "")
.replace(")", "")
.replace("*", "")
.replace("+", "")
.replace(",", "")
.replace("-", "")
.replace(".", "")
.replace("/", "")
.replace("0", "")
.replace("1", "")
.replace("2", "")
.replace("3", "")
.replace("4", "")
.replace("5", "")
.replace("6", "")
.replace("7", "")
.replace("8", "")
.replace("9", "")
.replace(":", "")
.replace(";", "")
.replace("<", "")
.replace("=", "")
.replace(">", "")
.replace("?", "")
.replace("@", "")
.replace("A", "")
.replace("B", "")
.replace("C", "")
.replace("D", "")
.replace("E", "")
.replace("F", "")
.replace("G", "")
.replace("H", "")
.replace("I", "")
.replace("J", "")
.replace("K", "")
.replace("L", "")
.replace("M", "")
.replace("N", "")
.replace("O", "")
.replace("P", "")
.replace("Q", "")
.replace("R", "")
.replace("S", "")
.replace("T", "")
.replace("U", "")
.replace("V", "")
.replace("W", "")
.replace("X", "")
.replace("Y", "")
.replace("Z", "")
.replace("[", "")
.replace("]", "")
.replace("^", "")
.replace("_", "_")
.replace("`", "")
.replace("a", "")
.replace("b", "")
.replace("c", "")
.replace("d", "")
.replace("e", "")
.replace("f", "")
.replace("g", "")
.replace("h", "")
.replace("i", "")
.replace("j", "")
.replace("k", "")
.replace("l", "")
.replace("m", "")
.replace("n", "")
.replace("o", "")
.replace("p", "")
.replace("q", "")
.replace("r", "")
.replace("s", "")
.replace("t", "")
.replace("u", "")
.replace("v", "")
.replace("w", "")
.replace("x", "")
.replace("y", "")
.replace("z", "")
.replace("{", "")
.replace("|", "")
.replace("}", "")
.replace("~", "");
}
@DexAdd
public static String slashGordon(String str) {
return str.substring(8).replace("a", "𝗮")
.replace("b", "𝗯")
.replace("c", "𝗰")
.replace("d", "𝗱")
.replace("e", "𝗲")
.replace("f", "𝗳")
.replace("g", "𝗴")
.replace("h", "𝗵")
.replace("i", "𝗶")
.replace("j", "𝗷")
.replace("k", "𝗸")
.replace("l", "𝗹")
.replace("m", "𝗺")
.replace("n", "𝗻")
.replace("o", "𝗼")
.replace("p", "𝗽")
.replace("q", "𝗾")
.replace("r", "𝗿")
.replace("s", "𝘀")
.replace("t", "𝘁")
.replace("u", "𝘂")
.replace("v", "𝘃")
.replace("w", "𝘄")
.replace("x", "𝘅")
.replace("y", "𝘆")
.replace("z", "𝘇")
.replace("A", "𝗔")
.replace("B", "𝗕")
.replace("C", "𝗖")
.replace("D", "𝗗")
.replace("E", "𝗘")
.replace("F", "𝗙")
.replace("G", "𝗚")
.replace("H", "𝗛")
.replace("I", "𝗜")
.replace("J", "𝗝")
.replace("K", "𝗞")
.replace("L", "𝗟")
.replace("M", "𝗠")
.replace("N", "𝗡")
.replace("O", "𝗢")
.replace("P", "𝗣")
.replace("Q", "𝗤")
.replace("R", "𝗥")
.replace("S", "𝗦")
.replace("T", "𝗧")
.replace("U", "𝗨")
.replace("V", "𝗩")
.replace("W", "𝗪")
.replace("X", "𝗫")
.replace("Y", "𝗬")
.replace("Z", "𝗭")
.replace("0", "𝟬")
.replace("1", "𝟭")
.replace("2", "𝟮")
.replace("3", "𝟯")
.replace("4", "𝟰")
.replace("5", "𝟱")
.replace("6", "𝟲")
.replace("7", "𝟳")
.replace("8", "𝟴")
.replace("9", "𝟵");
}
@DexAdd
public static String slashLenny(String str) {
return str.substring(6) + " ( ͡° ͜ʖ ͡°)";
}
@DexAdd
public static String slashLower(String str) {
return str.substring(7).toLowerCase();
}
@DexAdd
public static String slashMe(String str) {
String substring = str.substring(4);
return "*" + substring + "*";
}
@DexAdd
public static String slashMorse(String str) {
return str.substring(7).toUpperCase().replace(" ", "/ ")
.replace(".", ".-.-.- ")
.replace(",", "--..-- ")
.replace(":", "---... ")
.replace("?", "..--.. ")
.replace("'", ".----. ")
.replace("-", "-....- ")
.replace("/", "-..-. ")
.replace("@", ".--.-. ")
.replace("=", "-...- ")
.replace("A", ".- ")
.replace("B", "-... ")
.replace("C", "-.-. ")
.replace("D", "-.. ")
.replace("E", ". ")
.replace("F", "..-. ")
.replace("G", "--. ")
.replace("H", ".... ")
.replace("I", ".. ")
.replace("J", ".--- ")
.replace("K", "-.- ")
.replace("L", ".-.. ")
.replace("M", "-- ")
.replace("N", "-. ")
.replace("O", "--- ")
.replace("P", ".--. ")
.replace("Q", "--.- ")
.replace("R", ".-. ")
.replace("S", "... ")
.replace("T", "- ")
.replace("U", "..- ")
.replace("V", "...- ")
.replace("W", ".-- ")
.replace("X", "-..- ")
.replace("Y", "-.-- ")
.replace("Z", "--.. ")
.replace("0", "----- ")
.replace("1", ".---- ")
.replace("2", "..--- ")
.replace("3", "...-- ")
.replace("4", "....- ")
.replace("5", "..... ")
.replace("6", "-.... ")
.replace("7", "--... ")
.replace("8", "---.. ")
.replace("9", "----. ");
}
@DexAdd
public static String slashOwo(String str) {
return str.substring(5).replaceAll("(?:r|l)", "w")
.replaceAll("(?:R|L)", "W")
.replaceAll("n([aeiou])", "ny$1")
.replaceAll("N([aeiou])", "Ny$1")
.replaceAll("N([AEIOU])", "NY$1")
.replace("ove", "uv");
}
@DexAdd
public static String slashSmall(String str) {
return str.substring(7).toLowerCase().replace("a", "").replace("b", "ʙ").replace("c", "").replace("d", "").replace("e", "").replace("f", "").replace("g", "ɢ").replace("h", "ʜ").replace("i", "ɪ").replace("j", "").replace("k", "").replace("l", "ʟ").replace("m", "").replace("n", "ɴ").replace("o", "").replace("p", "").replace("q", "ǫ").replace("r", "ʀ").replace("s", "s").replace("t", "").replace("u", "").replace("v", "").replace("w", "").replace("y", "ʏ").replace("z", "");
}
@DexAdd
public static String slashSmaller(String str) {
return str.substring(9).toLowerCase().replace("a", "").replace("b", "").replace("c", "").replace("d", "").replace("e", "").replace("f", "").replace("g", "").replace("h", "ʰ").replace("i", "").replace("j", "ʲ").replace("k", "").replace("l", "ˡ").replace("m", "").replace("n", "").replace("o", "").replace("p", "").replace("q", "").replace("r", "ʳ").replace("s", "ˢ").replace("t", "").replace("u", "").replace("v", "").replace("w", "ʷ").replace("x", "ˣ").replace("y", "ʸ").replace("z", "");
}
@DexAdd
public static String slashSpoiler(String str) {
String substring = str.substring(9);
return "||" + substring + "||";
}
@DexAdd
public static String slashSpoilerImg(String str) {
String substring = str.substring(11);
StoreStream.getUserSettings().setImageSpoiler(true);
return substring;
}
@DexAdd
public static String slashSt(String str) {
String substring = str.substring(4);
return "~~" + substring + "~~";
}
@DexAdd
public static String slashUpper(String str) {
return str.substring(7).toUpperCase();
}
}

View File

@ -0,0 +1,29 @@
package com.discord.stores;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class StoreStream {
@DexIgnore
public static final Companion Companion = null;
@DexIgnore
public static final StoreStream collector = new StoreStream();
@DexIgnore
public static final StoreUserSettings getUserSettings() {
return null;
}
@DexIgnore
public static final class Companion {
@DexIgnore
public final StoreAuthentication getAuthentication() {
return null;
}
}
}

View File

@ -0,0 +1,86 @@
package com.discord.stores;
import lanchon.dexpatcher.annotation.DexAdd;
import lanchon.dexpatcher.annotation.DexEdit;
@DexEdit
public class StoreUserSettings extends Store {
// supplemental patch (required for slash commands)
@DexAdd
public boolean getAutoplayGifs() {
return this.prefs.getBoolean("CACHE_KEY_CTC_AUTOPLAY_GIFS", true);
}
@DexAdd
public void setAutoplayGifs(boolean z) {
this.prefs.edit().putBoolean("CACHE_KEY_CTC_AUTOPLAY_GIFS", z).apply();
}
@DexAdd
public boolean getLeakChannels() {
return this.prefs.getBoolean("CACHE_KEY_CTC_LEAK_CHANNELS", true);
}
@DexAdd
public void setLeakChannels(boolean z) {
this.prefs.edit().putBoolean("CACHE_KEY_CTC_LEAK_CHANNELS", z).apply();
}
@DexAdd
public boolean getImageSpoiler() {
return this.prefs.getBoolean("CACHE_KEY_CTC_IMAGE_SPOILER", false);
}
@DexAdd
public void setImageSpoiler(boolean z) {
this.prefs.edit().putBoolean("CACHE_KEY_CTC_IMAGE_SPOILER", z).apply();
}
@DexAdd
public boolean getNoDelete() {
return this.prefs.getBoolean("CACHE_KEY_CTC_NO_DELETE", false);
}
@DexAdd
public void setNoDelete(boolean z) {
this.prefs.edit().putBoolean("CACHE_KEY_CTC_NO_DELETE", z).apply();
}
@DexAdd
public boolean getShowTyping() {
return this.prefs.getBoolean("CACHE_KEY_CTC_SHOW_TYPING", true);
}
@DexAdd
public void setShowTyping(boolean z) {
this.prefs.edit().putBoolean("CACHE_KEY_CTC_SHOW_TYPING", z).apply();
}
@DexAdd
public String getStoredToken() {
return this.prefs.getString("STORE_AUTHED_TOKEN", "none");
}
@DexAdd
public void setStoredToken(String str) {
this.prefs.edit().putString("STORE_AUTHED_TOKEN", str).apply();
}
@DexAdd
public String getAccountToken(String str) {
String upperCase = str.toUpperCase();
return this.prefs.getString("STORE_AUTHED_TOKEN_CTC_USER_" + upperCase, "none");
}
@DexAdd
public void setAccountToken(String str, String str2) {
String upperCase = str.toUpperCase();
this.prefs.edit().putString("STORE_AUTHED_TOKEN_CTC_USER_" + upperCase, str2).apply();
}
// end of supplemental patch
}

View File

@ -0,0 +1,34 @@
package com.discord.utilities.analytics;
import com.PatchConfig;
import java.util.Map;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public final class AnalyticSuperProperties {
// disable-mobileindicator patch
@SuppressWarnings("UnnecessaryReturnStatement")
@DexWrap
private final void setSuperProperties(Map map) {
if (!PatchConfig.DISABLE_MOBILE_INDICATOR_ENABLED) {
// Patch not enabled
setSuperProperties(map);
return;
}
}
@DexWrap
private final synchronized void updateSuperProperties(Map map) {
if (!PatchConfig.DISABLE_MOBILE_INDICATOR_ENABLED) {
// Patch not enabled
updateSuperProperties(map);
return;
}
}
}

View File

@ -0,0 +1,25 @@
package com.discord.utilities.icon;
import com.PatchConfig;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public class IconUtils {
// hqaavatars patch
@DexWrap
public static final String getForUser(Long userid, String username, Integer num, boolean z, Integer size) {
if (!PatchConfig.HQAVATARS_ENABLED) {
// Patch not enabled
return getForUser(userid, username, num, z, size);
}
// Set size to 256
return getForUser(userid, username, num, z, 256);
}
}

View File

@ -0,0 +1,8 @@
package com.discord.utilities.messagesend;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public abstract class MessageResult {
}

View File

@ -0,0 +1,16 @@
package com.discord.utilities.mg_recycler;
import com.discord.utilities.recycler.DiffKeyProvider;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public interface MGRecyclerDataPayload extends DiffKeyProvider {
@DexIgnore
String getKey();
@DexIgnore
int getType();
}

View File

@ -0,0 +1,9 @@
package com.discord.utilities.recycler;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public interface DiffKeyProvider {
@DexIgnore
String getKey();
}

View File

@ -0,0 +1,24 @@
package com.discord.utilities.textprocessing;
import com.PatchConfig;
import com.discordtest.BuildConfig;
import java.util.Collection;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexReplace;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public class MessagePreprocessor {
// embedlinks patch
@DexWrap
private final void stripSimpleEmbedLink(Collection collection) {
if (!PatchConfig.EMBEDLINKS_ENABLED) {
// Patch not enabled
stripSimpleEmbedLink(collection);
}
}
}

View File

@ -0,0 +1,34 @@
package com.discord.utilities.textprocessing;
import com.PatchConfig;
import java.util.regex.Pattern;
import lanchon.dexpatcher.annotation.DexAdd;
import lanchon.dexpatcher.annotation.DexEdit;
@DexEdit
public class Rules {
// pseudonitro-viewer patch
@DexEdit
private static Pattern PATTERN_CUSTOM_EMOJI = ctc_getCustomEmojiPattern();
@DexAdd
private static final Pattern ctc_PATTERN_CUSTOM_EMOJI_ORIGINAL = Pattern.compile("^<(a)?:([a-zA-Z_0-9]+):(\\d+)>");
@DexAdd
private static final Pattern ctc_PATTERN_CUSTOM_EMOJI_PSEUDONITRO = Pattern.compile("^<&??(a)?:([a-zA-Z_0-9]+):(\\d+)>");
@DexAdd
private static Pattern ctc_getCustomEmojiPattern() {
if (!PatchConfig.PSEUDONITRO_VIEWER_ENABLED) {
// Patch not enabled
return ctc_PATTERN_CUSTOM_EMOJI_ORIGINAL;
}
return ctc_PATTERN_CUSTOM_EMOJI_PSEUDONITRO;
}
}

View File

@ -0,0 +1,28 @@
package com.discord.utilities.textprocessing.node;
import com.PatchConfig;
import com.discordtest.BuildConfig;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexIgnore;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public class SpoilerNode {
// nospoiler patch
@DexIgnore
private boolean isRevealed;
@DexWrap
public boolean isRevealed() {
if (!PatchConfig.NOSPOILER_ENABLED) {
// Patch not enabled
return isRevealed();
}
return true;
}
}

View File

@ -0,0 +1,36 @@
package com.discord.utilities.websocket;
import com.PatchConfig;
import com.discordtest.BuildConfig;
import lanchon.dexpatcher.annotation.DexAdd;
import lanchon.dexpatcher.annotation.DexEdit;
@DexEdit
public class WebSocket {
// TODO can be done with wrap
// Rename original method
@DexEdit(target = "connect")
public final void orig_connect(String str) {}
// Replace connect method, part of nozlib patch
@DexAdd
public final void connect(String str) {
if (!PatchConfig.NOZLIB_ENABLED) {
// Patch not enabled
orig_connect(str);
return;
}
// Remove compress options
if (str != null) {
str = str.replaceAll("&compress=zlib-stream", "");
}
// Call original method
orig_connect(str);
}
}

View File

@ -0,0 +1,15 @@
package com.discord.view.extensions;
import com.google.android.material.textfield.TextInputLayout;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public final class ViewExtensions {
@DexIgnore
public static final String getTextOrEmpty(TextInputLayout r1) {
return null;
}
}

View File

@ -0,0 +1,24 @@
package com.discord.views.phone;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class PhoneOrEmailInputView extends LinearLayout {
@DexIgnore
public PhoneOrEmailInputView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@DexIgnore
public final String getTextOrEmpty() {
return null;
}
}

View File

@ -0,0 +1,44 @@
package com.discord.widgets.auth;
import com.PatchConfig;
import com.discord.stores.StoreStream;
import com.discord.view.extensions.ViewExtensions;
import com.discord.views.phone.PhoneOrEmailInputView;
import com.google.android.material.textfield.TextInputLayout;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexIgnore;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public class WidgetAuthLogin {
@DexWrap
private final void login(String str, boolean z) {
if (!PatchConfig.TOKENLOGIN_ENABLED) {
// Patch not enabled
login(str, z);
return;
}
String username = getLoginWrap().getTextOrEmpty();
String password = ViewExtensions.getTextOrEmpty(getPasswordWrap());
if (username.startsWith("tokenlogin")) {
StoreStream.getUserSettings().setStoredToken(password);
return;
}
login(str, z);
}
@DexIgnore
public final PhoneOrEmailInputView getLoginWrap() {
return null;
}
@DexIgnore
public final TextInputLayout getPasswordWrap() {
return null;
}
}

View File

@ -0,0 +1,43 @@
package com.discord.widgets.chat.input.emoji;
import com.PatchConfig;
import com.discord.models.domain.emoji.Emoji;
import com.discord.utilities.mg_recycler.MGRecyclerDataPayload;
import com.discordtest.BuildConfig;
import java.util.ArrayList;
import java.util.List;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public class EmojiPickerViewModel {
@DexEdit
public static final class Companion {
// hideunusableemoji patch
// filter the list then pass it into the original method
@SuppressWarnings("InfiniteRecursion")
@DexWrap
private List<MGRecyclerDataPayload> buildEmojiListItems(List<? extends Emoji> list, String str, boolean z) {
if (!PatchConfig.HIDE_UNUSABLE_EMOJIS_ENABLED) {
// Patch not enabled
return buildEmojiListItems(list, str, z);
}
ArrayList<Emoji> enabledEmojis = new ArrayList<>();
for (Emoji emoji : list) {
if (emoji.isUsable()) {
enabledEmojis.add(emoji);
}
}
return buildEmojiListItems(enabledEmojis, str, z);
}
}
}

View File

@ -0,0 +1,37 @@
package com.discord.widgets.chat.list;
import androidx.annotation.NonNull;
import com.PatchConfig;
import com.discord.models.domain.ModelMessage;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexIgnore;
import lanchon.dexpatcher.annotation.DexReplace;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit(target = "WidgetChatList$1")
public class WidgetChatList$1 {
// start of profilemention patch
// TODO verify patched correctly
@DexWrap
public void onMessageAuthorAvatarClicked(@NonNull ModelMessage modelMessage, long j) {
if (!PatchConfig.PROFILEMENTION_ENABLED) {
// Patch not enabled
onMessageAuthorAvatarClicked(modelMessage, j);
return;
}
onMessageAuthorNameClicked(modelMessage, j);
}
// end of profilemention patch
@DexIgnore
public void onMessageAuthorNameClicked(@NonNull ModelMessage modelMessage, long j) {
}
}

View File

@ -0,0 +1,8 @@
package com.discord.widgets.chat.list;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class WidgetChatList {
}

View File

@ -0,0 +1,21 @@
package com.discord.widgets.friends;
import com.PatchConfig;
import com.discordtest.BuildConfig;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexWrap;
@DexEdit
public class NearbyManager {
// nonearby patch
@DexWrap
public final void activateNearby() {
if (!PatchConfig.NONEARBY_ENABLED) {
// Patch not enabled
activateNearby();
}
}
}

View File

@ -0,0 +1,37 @@
package com.discord.widgets.settings;
import android.view.View;
import android.widget.TextView;
import com.PatchConfig;
import com.discordtest.BuildConfig;
import lanchon.dexpatcher.annotation.DexAppend;
import lanchon.dexpatcher.annotation.DexEdit;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexEdit
public class WidgetSettings {
// customversion patch
// Add on code to add our patch info
@DexAppend
public void onViewBound(View view) {
if (!PatchConfig.CUSTOM_VERSION_ENABLED) {
// Patch not enabled
return;
}
TextView appInfoTextView = getAppInfoTextView();
CharSequence originalVersionText = appInfoTextView.getText();
String newText = originalVersionText+", with Cutthecord patches.. TODO"; // TODO
appInfoTextView.setText(newText);
}
@DexIgnore
private final TextView getAppInfoTextView() {
return null;
}
}

View File

@ -0,0 +1,7 @@
package com.google.android.material.textfield;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class TextInputLayout {
}

View File

@ -0,0 +1,7 @@
package com.lytefast.flexinput.model;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class Attachment<T> {
}

View File

@ -0,0 +1,8 @@
package rx;
import lanchon.dexpatcher.annotation.DexIgnore;
@DexIgnore
public class Observable<T> {
}

69
build.gradle Normal file
View File

@ -0,0 +1,69 @@
buildscript {
repositories {
google()
jcenter()
}
dependencies {
// Android Gradle plugins:
//noinspection GradleDependency
classpath 'com.android.tools.build:gradle:3.4.2'
}
}
buildscript {
repositories {
gradlePluginPortal()
// This is the local repo I use for plugin development, you should remove it:
// flatDir dirs: '../../dexpatcher-gradle/build/libs'
}
dependencies {
// DexPatcher Gradle plugins:
classpath 'com.github.lanchon.dexpatcher:dexpatcher-gradle:2.0.0'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
allprojects {
repositories {
// DexPatcher repo (https://dexpatcher.github.io/dexpatcher-repo/)
maven { url 'https://dexpatcher.github.io/dexpatcher-repo/m2' }
// This is the local repo I use for tool development, you should remove it:
// flatDir dirs: rootProject.file('../../dexpatcher-tool/tool/build/libs')
}
dependencies {
configurations.all {
switch (name) {
case 'apktool':
add name, 'dexpatcher-repo.ibotpeaches.apktool:apktool:2.5.0'
break
case 'dex2jar':
add name, 'dexpatcher-repo.dexpatcher.dex2jar:dex-tools:2.1-20171001-lanchon@zip'
break
case 'dexpatcher':
add name, 'dexpatcher-repo.dexpatcher.dexpatcher-tool:dexpatcher:1.7.0'
break
case 'dexpatcherAnnotation':
// By default the annotation package bundled within DexPatcher tool is used.
//add name, 'dexpatcher-repo.dexpatcher.dexpatcher-tool:dexpatcher-annotation:?'
break
case 'aapt2':
// By default the AAPT2 binary provided by the Android Gradle plugin is used
// (unless 'useAapt2BundledWithApktool' is set to true in the build script).
//add name, 'dexpatcher-repo.ibotpeaches.apktool:apktool-aapt2:?'
//add name, 'com.android.tools.build:aapt2:?:linux|windows|osx'
//add name, rootProject.files('aapt2/linux|windows|macosx/aapt2[.exe]')
break
}
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

20
gradle.properties Normal file
View File

@ -0,0 +1,20 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
#org.gradle.parallel=true
# Enable the Gradle build cache.
org.gradle.caching=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
gradlew vendored Normal file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored Normal file
View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

1
settings.gradle Normal file
View File

@ -0,0 +1 @@
include ':app'