mirror of https://github.com/NekoX-Dev/NekoX.git
This commit is contained in:
parent
93d325de46
commit
ea6b589b6d
|
@ -147,6 +147,8 @@ public class FileLoadOperation {
|
|||
private ArrayList<RequestInfo> requestInfos;
|
||||
private ArrayList<RequestInfo> delayedRequestInfos;
|
||||
|
||||
private String fileName;
|
||||
|
||||
private File cacheFileTemp;
|
||||
private File cacheFileGzipTemp;
|
||||
private File cacheFileFinal;
|
||||
|
@ -266,7 +268,8 @@ public class FileLoadOperation {
|
|||
ext = ImageLoader.getHttpUrlExtension(webDocument.url, defaultExt);
|
||||
}
|
||||
|
||||
public FileLoadOperation(TLRPC.Document documentLocation, Object parent) {
|
||||
public FileLoadOperation(TLRPC.Document documentLocation, Object parent,String fileName) {
|
||||
this.fileName = fileName;
|
||||
try {
|
||||
parentObject = parent;
|
||||
if (documentLocation instanceof TLRPC.TL_documentEncrypted) {
|
||||
|
@ -718,6 +721,8 @@ public class FileLoadOperation {
|
|||
if (parentObject instanceof TLRPC.TL_theme) {
|
||||
TLRPC.TL_theme theme = (TLRPC.TL_theme) parentObject;
|
||||
cacheFileFinal = new File(ApplicationLoader.getFilesDirFixed(), "remote" + theme.id + ".attheme");
|
||||
} else if (fileName != null) {
|
||||
cacheFileFinal = new File(storePath, fileName);
|
||||
} else {
|
||||
cacheFileFinal = new File(storePath, fileNameFinal);
|
||||
}
|
||||
|
|
|
@ -612,7 +612,7 @@ public class FileLoader extends BaseController {
|
|||
operation = new FileLoadOperation(imageLocation, parentObject, locationExt, locationSize);
|
||||
type = MEDIA_DIR_IMAGE;
|
||||
} else if (document != null) {
|
||||
operation = new FileLoadOperation(document, parentObject);
|
||||
operation = new FileLoadOperation(document, parentObject,fileName);
|
||||
if (MessageObject.isVoiceDocument(document)) {
|
||||
type = MEDIA_DIR_AUDIO;
|
||||
} else if (MessageObject.isVideoDocument(document)) {
|
||||
|
|
|
@ -246,9 +246,6 @@ public class FileUploadOperation {
|
|||
started = true;
|
||||
if (stream == null) {
|
||||
File cacheFile = new File(uploadingFilePath);
|
||||
if (AndroidUtilities.isInternalUri(Uri.fromFile(cacheFile))) {
|
||||
throw new Exception("trying to upload internal file");
|
||||
}
|
||||
stream = new RandomAccessFile(cacheFile, "r");
|
||||
if (estimatedSize != 0) {
|
||||
totalFileSize = estimatedSize;
|
||||
|
|
|
@ -472,6 +472,16 @@ public class ActionBarMenuItem extends FrameLayout {
|
|||
this.anchor = anchor;
|
||||
}
|
||||
|
||||
public boolean isShowOnTop() {
|
||||
return showOnTop;
|
||||
}
|
||||
|
||||
public void setShowOnTop(boolean showOnTop) {
|
||||
this.showOnTop = showOnTop;
|
||||
}
|
||||
|
||||
private boolean showOnTop;
|
||||
|
||||
public void toggleSubMenu() {
|
||||
if (popupLayout == null || parentMenu != null && parentMenu.isActionMode && parentMenu.parentActionBar != null && !parentMenu.parentActionBar.isActionModeShowed()) {
|
||||
return;
|
||||
|
@ -958,7 +968,9 @@ public class ActionBarMenuItem extends FrameLayout {
|
|||
int[] location = new int[2];
|
||||
anchor.getLocationOnScreen(location);
|
||||
int y = location[1];
|
||||
if (height - y < popupLayout.getMeasuredHeight() + offsetY) {
|
||||
if (showOnTop) {
|
||||
offsetY -= popupLayout.getMeasuredHeight();
|
||||
} else if (height - y < popupLayout.getMeasuredHeight() + offsetY) {
|
||||
if (height - (height - y) >= popupLayout.getMeasuredHeight()) {
|
||||
offsetY -= popupLayout.getMeasuredHeight();
|
||||
} else if (popupLayout.getMeasuredHeight() > height) {
|
||||
|
|
|
@ -183,7 +183,6 @@ import org.telegram.ui.Components.VideoPlayer;
|
|||
import org.telegram.ui.Components.WebPlayerView;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -195,8 +194,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import tw.nekomimi.nekogram.NekoConfig;
|
||||
import tw.nekomimi.nekogram.translator.TranslateDb;
|
||||
import tw.nekomimi.nekogram.translator.Translator;
|
||||
import tw.nekomimi.nekogram.transtale.Translator;
|
||||
import tw.nekomimi.nekogram.transtale.TranslateDb;
|
||||
import tw.nekomimi.nekogram.utils.AlertUtil;
|
||||
import tw.nekomimi.nekogram.utils.UIUtil;
|
||||
|
||||
|
@ -4094,61 +4093,68 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
|
|||
ArrayList<Object> array = new ArrayList<>(adapter[0].textBlocks);
|
||||
AtomicInteger errorCount = new AtomicInteger();
|
||||
AtomicInteger taskCount = new AtomicInteger(array.size());
|
||||
for (int b = 0, N = array.size(); b < N; b++) {
|
||||
Object object = array.get(b);
|
||||
TLRPC.PageBlock block = copy.get(object);
|
||||
String textToSearchIn = null;
|
||||
if (object instanceof TLRPC.RichText) {
|
||||
TLRPC.RichText richText = (TLRPC.RichText) object;
|
||||
CharSequence innerText = getText(adapter[0], null, richText, richText, block, 1000);
|
||||
if (!TextUtils.isEmpty(innerText)) {
|
||||
textToSearchIn = innerText.toString();
|
||||
try {
|
||||
for (int b = 0, N = array.size(); b < N; b++) {
|
||||
Object object = array.get(b);
|
||||
TLRPC.PageBlock block = copy.get(object);
|
||||
String textToSearchIn = null;
|
||||
if (object instanceof TLRPC.RichText) {
|
||||
TLRPC.RichText richText = (TLRPC.RichText) object;
|
||||
CharSequence innerText = getText(adapter[0], null, richText, richText, block, 1000);
|
||||
if (!TextUtils.isEmpty(innerText)) {
|
||||
textToSearchIn = innerText.toString();
|
||||
}
|
||||
} else if (object instanceof String) {
|
||||
textToSearchIn = ((String) object);
|
||||
}
|
||||
} else if (object instanceof String) {
|
||||
textToSearchIn = ((String) object);
|
||||
}
|
||||
if (textToSearchIn != null) {
|
||||
if (TranslateDb.contains(textToSearchIn)) {
|
||||
taskCount.decrementAndGet();
|
||||
continue;
|
||||
}
|
||||
String finalTextToSearchIn = textToSearchIn;
|
||||
transPool.execute(() -> {
|
||||
if (textToSearchIn != null) {
|
||||
if (TranslateDb.contains(textToSearchIn)) {
|
||||
taskCount.decrementAndGet();
|
||||
continue;
|
||||
}
|
||||
String finalTextToSearchIn = textToSearchIn;
|
||||
|
||||
if (cancel.get()) return;
|
||||
transPool.execute(() -> {
|
||||
|
||||
String localeText;
|
||||
try {
|
||||
localeText = Translator.translateSync(finalTextToSearchIn);
|
||||
if (cancel.get()) return;
|
||||
} catch (IOException e) {
|
||||
if (cancel.get()) return;
|
||||
boolean finaL = taskCount.decrementAndGet() == 0;
|
||||
if (errorCount.incrementAndGet() > 3 || finaL) {
|
||||
UIUtil.runOnUIThread(dialog::dismiss);
|
||||
adapter[0].trans = false;
|
||||
transMenu.setTextAndIcon(LocaleController.getString("Translate", R.string.Translate), R.drawable.ic_translate);
|
||||
AlertUtil.showSimpleAlert(parentActivity, e.getMessage());
|
||||
cancel.set(true);
|
||||
transPool.shutdown();
|
||||
|
||||
String localeText;
|
||||
try {
|
||||
localeText = Translator.translate(finalTextToSearchIn);
|
||||
if (cancel.get()) return;
|
||||
} catch (Exception e) {
|
||||
if (cancel.get()) return;
|
||||
boolean finaL = taskCount.decrementAndGet() == 0;
|
||||
if (errorCount.incrementAndGet() > 3 || finaL) {
|
||||
UIUtil.runOnUIThread(dialog::dismiss);
|
||||
adapter[0].trans = false;
|
||||
transMenu.setTextAndIcon(LocaleController.getString("Translate", R.string.Translate), R.drawable.ic_translate);
|
||||
AlertUtil.showSimpleAlert(parentActivity, e.getMessage());
|
||||
cancel.set(true);
|
||||
transPool.shutdown();
|
||||
AlertUtil.showTransFailedDialog(parentActivity, e instanceof UnsupportedOperationException, e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage(), this::doTransLATE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
TranslateDb.save(finalTextToSearchIn, localeText);
|
||||
UIUtil.runOnUIThread(this::updatePaintSize);
|
||||
TranslateDb.save(finalTextToSearchIn, localeText);
|
||||
UIUtil.runOnUIThread(this::updatePaintSize);
|
||||
|
||||
boolean finaL = taskCount.decrementAndGet() == 0;
|
||||
boolean finaL = taskCount.decrementAndGet() < 1;
|
||||
|
||||
if (finaL) {
|
||||
if (finaL) {
|
||||
|
||||
UIUtil.runOnUIThread(dialog::dismiss);
|
||||
transPool.shutdown();
|
||||
UIUtil.runOnUIThread(dialog::dismiss);
|
||||
transPool.shutdown();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
dialog.dismiss();
|
||||
UIUtil.runOnUIThread(this::updatePaintSize);
|
||||
}
|
||||
if (taskCount.get() == 0) {
|
||||
dialog.dismiss();
|
||||
|
|
|
@ -94,6 +94,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.telegram.PhoneFormat.PhoneFormat;
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
|
@ -214,6 +215,7 @@ import java.util.Calendar;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -221,9 +223,9 @@ import tw.nekomimi.nekogram.MessageDetailsActivity;
|
|||
import tw.nekomimi.nekogram.MessageHelper;
|
||||
import tw.nekomimi.nekogram.NekoConfig;
|
||||
import tw.nekomimi.nekogram.NekoXConfig;
|
||||
import tw.nekomimi.nekogram.translator.TranslateBottomSheet;
|
||||
import tw.nekomimi.nekogram.translator.TranslateDb;
|
||||
import tw.nekomimi.nekogram.translator.Translator;
|
||||
import tw.nekomimi.nekogram.transtale.Translator;
|
||||
import tw.nekomimi.nekogram.transtale.TranslateBottomSheet;
|
||||
import tw.nekomimi.nekogram.transtale.TranslateDb;
|
||||
import tw.nekomimi.nekogram.utils.AlertUtil;
|
||||
import tw.nekomimi.nekogram.utils.StrUtil;
|
||||
|
||||
|
@ -15326,9 +15328,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
chatAdapter.updateRowWithMessageObject(messageObject, true);
|
||||
}
|
||||
} else {
|
||||
Translator.translate(original, new Translator.TranslateCallBack() {
|
||||
|
||||
Translator.translate(original, new Translator.Companion.TranslateCallBack() {
|
||||
@Override
|
||||
public void onSuccess(String translation) {
|
||||
public void onSuccess(@NotNull String translation) {
|
||||
TranslateDb.save(original,translation);
|
||||
if (finalMessageCell != null) {
|
||||
MessageObject messageObject = finalMessageCell.getMessageObject();
|
||||
|
@ -15344,21 +15347,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
try {
|
||||
Toast.makeText(getParentActivity(), LocaleController.getString("TranslateFailed", R.string.TranslateFailed), Toast.LENGTH_SHORT).show();
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnsupported() {
|
||||
try {
|
||||
Toast.makeText(getParentActivity(), LocaleController.getString("TranslateApiUnsupported", R.string.TranslateApiUnsupported), Toast.LENGTH_SHORT).show();
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
public void onFailed(boolean unsupported, @NotNull String message) {
|
||||
AlertUtil.showTransFailedDialog(getParentActivity(),unsupported,message,() -> {
|
||||
Translator.translate(original,this);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import org.json.JSONArray;
|
||||
|
@ -60,25 +59,13 @@ import org.telegram.messenger.FileLog;
|
|||
import org.telegram.messenger.ImageLocation;
|
||||
import org.telegram.messenger.ImageReceiver;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.SharedConfig;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.tgnet.TLRPC;
|
||||
import tw.nekomimi.nekogram.utils.HttpUtil;
|
||||
import tw.nekomimi.nekogram.utils.ThreadUtil;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -87,7 +74,6 @@ import java.util.Map;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerDelegate, AudioManager.OnAudioFocusChangeListener {
|
||||
|
||||
|
@ -456,7 +442,7 @@ public class WebPlayerView extends ViewGroup implements VideoPlayer.VideoPlayerD
|
|||
|
||||
protected String downloadUrlContent(AsyncTask parentTask, String url, HashMap<String, String> headers, boolean tryGzip) {
|
||||
|
||||
OkHttpClient client = HttpUtil.getOkhttpClientWithCurrProxy().newBuilder()
|
||||
OkHttpClient client = HttpUtil.getOkHttpClientWithCurrProxy().newBuilder()
|
||||
.followRedirects(true)
|
||||
.followSslRedirects(true)
|
||||
.build();
|
||||
|
|
|
@ -44,7 +44,8 @@ import java.util.TimerTask;
|
|||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import tw.nekomimi.nekogram.translator.TranslateDb;
|
||||
import tw.nekomimi.nekogram.transtale.TranslateDb;
|
||||
import tw.nekomimi.nekogram.utils.UIUtil;
|
||||
|
||||
public class LanguageSelectActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
|
||||
|
||||
|
@ -154,8 +155,8 @@ public class LanguageSelectActivity extends BaseFragment implements Notification
|
|||
if (localeInfo != null) {
|
||||
LocaleController.getInstance().applyLanguage(localeInfo, true, false, false, true, currentAccount);
|
||||
parentLayout.rebuildAllFragmentViews(false, false);
|
||||
TranslateDb.clear();
|
||||
}
|
||||
UIUtil.runOnIoDispatcher(TranslateDb::clear);
|
||||
finishFragment();
|
||||
});
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import org.telegram.messenger.NotificationsService;
|
|||
import org.telegram.messenger.SharedConfig;
|
||||
|
||||
import tw.nekomimi.nekogram.database.NitritesKt;
|
||||
import tw.nekomimi.nekogram.transtale.TranslateDb;
|
||||
import tw.nekomimi.nekogram.utils.UIUtil;
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
public class NekoConfig {
|
||||
|
@ -369,6 +371,7 @@ public class NekoConfig {
|
|||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("translationProvider", translationProvider);
|
||||
editor.apply();
|
||||
UIUtil.runOnIoDispatcher(TranslateDb::clear);
|
||||
}
|
||||
|
||||
public static void toggleDisablePhotoSideAction() {
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.telegram.ui.Components.SeekBarView;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import kotlin.Unit;
|
||||
import tw.nekomimi.nekogram.utils.PopupBuilder;
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
|
@ -245,13 +246,14 @@ public class NekoSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder builder = new PopupBuilder(view);
|
||||
|
||||
builder.setItemsIndexed(new String[]{
|
||||
builder.setItems(new String[]{
|
||||
LocaleController.getString("MapPreviewProviderTelegram", R.string.MapPreviewProviderTelegram),
|
||||
LocaleController.getString("MapPreviewProviderYandex", R.string.MapPreviewProviderYandex),
|
||||
LocaleController.getString("MapPreviewProviderNobody", R.string.MapPreviewProviderNobody)
|
||||
}, (it) -> {
|
||||
NekoConfig.setMapPreviewProvider(it);
|
||||
}, (i, __) -> {
|
||||
NekoConfig.setMapPreviewProvider(i);
|
||||
listAdapter.notifyItemChanged(position);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
builder.show();
|
||||
|
@ -260,12 +262,13 @@ public class NekoSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder builder = new PopupBuilder(view);
|
||||
|
||||
builder.setItemsIndexed(new String[]{
|
||||
builder.setItems(new String[]{
|
||||
LocaleController.getString("FirstLast", R.string.FirstLast),
|
||||
LocaleController.getString("LastFirst", R.string.LastFirst)
|
||||
}, (i) -> {
|
||||
}, (i, __) -> {
|
||||
NekoConfig.setNameOrder(i + 1);
|
||||
listAdapter.notifyItemChanged(position);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
builder.show();
|
||||
|
@ -274,13 +277,14 @@ public class NekoSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder builder = new PopupBuilder(view);
|
||||
|
||||
builder.setItemsIndexed(new String[]{
|
||||
builder.setItems(new String[]{
|
||||
LocaleController.getString("DependsOnDate", R.string.DependsOnDate),
|
||||
LocaleController.getString("Christmas", R.string.Christmas),
|
||||
LocaleController.getString("Valentine", R.string.Valentine)
|
||||
}, (i) -> {
|
||||
}, (i, __) -> {
|
||||
NekoConfig.setEventType(i);
|
||||
listAdapter.notifyItemChanged(position);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
builder.show();
|
||||
|
@ -289,15 +293,17 @@ public class NekoSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder builder = new PopupBuilder(view);
|
||||
|
||||
builder.setItemsIndexed(new String[]{
|
||||
builder.setItems(new String[]{
|
||||
LocaleController.getString("DependsOnDate", R.string.DependsOnDate),
|
||||
LocaleController.getString("Snowflakes", R.string.Snowflakes),
|
||||
LocaleController.getString("Fireworks", R.string.Fireworks)
|
||||
}, (i) -> {
|
||||
}, (i, __) -> {
|
||||
|
||||
NekoConfig.setActionBarDecoration(i);
|
||||
listAdapter.notifyItemChanged(position);
|
||||
|
||||
return null;
|
||||
|
||||
});
|
||||
|
||||
builder.show();
|
||||
|
@ -404,33 +410,47 @@ public class NekoSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder builder = new PopupBuilder(view);
|
||||
|
||||
builder.setItemsIndexed(new String[] {
|
||||
builder.setItems(new String[]{
|
||||
LocaleController.getString("ProviderGoogleTranslate", R.string.ProviderGoogleTranslate),
|
||||
LocaleController.getString("ProviderGoogleTranslateCN", R.string.ProviderGoogleTranslateCN),
|
||||
LocaleController.getString("ProviderLingocloud", R.string.ProviderLingocloud),
|
||||
|
||||
LocaleController.getString("ProviderGoogleTranslateWeb", R.string.ProviderGoogleTranslateWeb),
|
||||
LocaleController.getString("ProviderGoogleTranslateCNWeb", R.string.ProviderGoogleTranslateCNWeb),
|
||||
LocaleController.getString("ProviderBaiduFanyiWeb", R.string.ProviderBaiduFanyiWeb)
|
||||
|
||||
},(i) -> {
|
||||
}, (i, __) -> {
|
||||
|
||||
int target;
|
||||
|
||||
switch (i) {
|
||||
|
||||
default: target = 1;break;
|
||||
case 1: target = 2;break;
|
||||
case 2: target = 3;break;
|
||||
case 3: target = -1;break;
|
||||
case 4: target = -2;break;
|
||||
case 5: target = -3;break;
|
||||
|
||||
default:
|
||||
target = 1;
|
||||
break;
|
||||
case 1:
|
||||
target = 2;
|
||||
break;
|
||||
case 2:
|
||||
target = 3;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
target = -1;
|
||||
break;
|
||||
case 9:
|
||||
target = -2;
|
||||
break;
|
||||
case 10:
|
||||
target = -3;
|
||||
break;
|
||||
}
|
||||
|
||||
NekoConfig.setTranslationProvider(target);
|
||||
listAdapter.notifyItemChanged(translationProviderRow);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
builder.show();
|
||||
|
@ -1069,9 +1089,10 @@ public class NekoSettingsActivity extends BaseFragment {
|
|||
value = LocaleController.getString("ProviderBaiduFanyiWeb", R.string.ProviderBaiduFanyiWeb);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
value = LocaleController.getString("ProviderLingocloud", R.string.ProviderLingocloud);
|
||||
break;
|
||||
default:
|
||||
value = "Unknown";
|
||||
}
|
||||
textCell.setTextAndValue(LocaleController.getString("TranslationProvider", R.string.TranslationProvider), value, false);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.telegram.ui.Components.LayoutHelper;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import kotlin.Unit;
|
||||
import tw.nekomimi.nekogram.utils.PopupBuilder;
|
||||
import tw.nekomimi.nekogram.utils.StrUtil;
|
||||
|
||||
|
@ -309,7 +310,13 @@ public class ShadowsocksRSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder select = new PopupBuilder(v);
|
||||
|
||||
select.setItems(ShadowsocksRLoader.Companion.getMethods(), methodField.getValueTextView()::setText);
|
||||
select.setItems(ShadowsocksRLoader.Companion.getMethods(), (__,value) -> {
|
||||
|
||||
methodField.getValueTextView().setText(value);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
select.show();
|
||||
|
||||
|
@ -327,7 +334,13 @@ public class ShadowsocksRSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder select = new PopupBuilder(v);
|
||||
|
||||
select.setItems(ShadowsocksRLoader.Companion.getProtocols(), protocolField.getValueTextView()::setText);
|
||||
select.setItems(ShadowsocksRLoader.Companion.getProtocols(), (__,value) -> {
|
||||
|
||||
protocolField.getValueTextView().setText(value);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
select.show();
|
||||
|
||||
|
@ -347,7 +360,13 @@ public class ShadowsocksRSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder select = new PopupBuilder(v);
|
||||
|
||||
select.setItems(ShadowsocksRLoader.Companion.getObfses(), obfsField.getValueTextView()::setText);
|
||||
select.setItems(ShadowsocksRLoader.Companion.getObfses(), (__,value) -> {
|
||||
|
||||
obfsField.getValueTextView().setText(value);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
select.show();
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.telegram.ui.Components.LayoutHelper;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import kotlin.Unit;
|
||||
import tw.nekomimi.nekogram.utils.PopupBuilder;
|
||||
import tw.nekomimi.nekogram.utils.StrUtil;
|
||||
|
||||
|
@ -69,8 +70,6 @@ public class ShadowsocksSettingsActivity extends BaseFragment {
|
|||
|
||||
private static final int done_button = 1;
|
||||
|
||||
private static String[] methodSet = ShadowsocksLoader.Companion.getMethods();
|
||||
|
||||
public class TypeCell extends FrameLayout {
|
||||
|
||||
private TextView textView;
|
||||
|
@ -288,7 +287,13 @@ public class ShadowsocksSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder select = new PopupBuilder(v);
|
||||
|
||||
select.setItems(methodSet, methodField.getValueTextView()::setText);
|
||||
select.setItems(ShadowsocksLoader.Companion.getMethods(),(__,value) -> {
|
||||
|
||||
methodField.getValueTextView().setText(value);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
select.show();
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.telegram.ui.Components.LayoutHelper;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import kotlin.Unit;
|
||||
import tw.nekomimi.nekogram.utils.PopupBuilder;
|
||||
import tw.nekomimi.nekogram.utils.StrUtil;
|
||||
|
||||
|
@ -336,7 +337,13 @@ public class VmessSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder select = new PopupBuilder(v);
|
||||
|
||||
select.setItems(securitySet, securityField.getValueTextView()::setText);
|
||||
select.setItems(securitySet, (__,value) -> {
|
||||
|
||||
securityField.getValueTextView().setText(value);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
select.show();
|
||||
|
||||
|
@ -354,7 +361,13 @@ public class VmessSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder select = new PopupBuilder(v);
|
||||
|
||||
select.setItems(networkSet, networkField.getValueTextView()::setText);
|
||||
select.setItems(networkSet, (__,value) -> {
|
||||
|
||||
networkField.getValueTextView().setText(value);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
select.show();
|
||||
|
||||
|
@ -372,7 +385,13 @@ public class VmessSettingsActivity extends BaseFragment {
|
|||
|
||||
PopupBuilder select = new PopupBuilder(v);
|
||||
|
||||
select.setItems(headTypeSet, headTypeField.getValueTextView()::setText);
|
||||
select.setItems(headTypeSet, (__,value) -> {
|
||||
|
||||
headTypeField.getValueTextView().setText(value);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
select.show();
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.content.SharedPreferences
|
|||
import org.dizitart.no2.*
|
||||
import org.dizitart.no2.filters.Filters
|
||||
import org.telegram.messenger.FileLog
|
||||
import tw.nekomimi.nekogram.utils.UIUtil
|
||||
|
||||
class DbPref(val connection: NitriteCollection) : SharedPreferences {
|
||||
|
||||
|
@ -28,7 +27,7 @@ class DbPref(val connection: NitriteCollection) : SharedPreferences {
|
|||
}
|
||||
|
||||
override fun contains(key: String): Boolean {
|
||||
return connection.find(Filters.eq("key", key)).hasMore()
|
||||
return connection.find(Filters.eq("key", key)).count() > 0
|
||||
}
|
||||
|
||||
override fun getBoolean(key: String, defValue: Boolean) = getAs(key, defValue)
|
||||
|
@ -65,9 +64,9 @@ class DbPref(val connection: NitriteCollection) : SharedPreferences {
|
|||
|
||||
inner class PrefEditor : SharedPreferences.Editor {
|
||||
|
||||
var clear = false
|
||||
val toRemove = HashSet<String>()
|
||||
val toApply = HashMap<String, Any?>()
|
||||
private var clear = false
|
||||
private val toRemove = HashSet<String>()
|
||||
private val toApply = HashMap<String, Any?>()
|
||||
|
||||
override fun clear(): PrefEditor {
|
||||
clear = true
|
||||
|
@ -137,9 +136,7 @@ class DbPref(val connection: NitriteCollection) : SharedPreferences {
|
|||
}
|
||||
|
||||
override fun apply() {
|
||||
UIUtil.runOnIoDispatcher(Runnable {
|
||||
commit()
|
||||
})
|
||||
commit()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,162 +0,0 @@
|
|||
package tw.nekomimi.nekogram.translator;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONTokener;
|
||||
import org.telegram.messenger.FileLog;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import tw.nekomimi.nekogram.NekoConfig;
|
||||
|
||||
public class GoogleWebTranslator extends Translator {
|
||||
|
||||
private static GoogleWebTranslator instance;
|
||||
private List<String> targetLanguages = Arrays.asList(
|
||||
"sq", "ar", "am", "az", "ga", "et", "eu", "be", "bg", "is", "pl", "bs", "fa",
|
||||
"af", "da", "de", "ru", "fr", "tl", "fi", "fy", "km", "ka", "gu", "kk", "ht",
|
||||
"ko", "ha", "nl", "ky", "gl", "ca", "cs", "kn", "co", "hr", "ku", "la", "lv",
|
||||
"lo", "lt", "lb", "ro", "mg", "mt", "mr", "ml", "ms", "mk", "mi", "mn", "bn",
|
||||
"my", "hmn", "xh", "zu", "ne", "no", "pa", "pt", "ps", "ny", "ja", "sv", "sm",
|
||||
"sr", "st", "si", "eo", "sk", "sl", "sw", "gd", "ceb", "so", "tg", "te", "ta",
|
||||
"th", "tr", "cy", "ur", "uk", "uz", "es", "iw", "el", "haw", "sd", "hu", "sn",
|
||||
"hy", "ig", "it", "yi", "hi", "su", "id", "jw", "en", "yo", "vi", "zh-TW", "zh-CN", "zh");
|
||||
private long[] tkk;
|
||||
|
||||
static GoogleWebTranslator getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (GoogleWebTranslator.class) {
|
||||
if (instance == null) {
|
||||
instance = new GoogleWebTranslator();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String translate(String query, String tl) {
|
||||
String result = translateImpl(query, tl);
|
||||
if (result == null) {
|
||||
tkk = null;
|
||||
return translateImpl(query, tl);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTargetLanguages() {
|
||||
return targetLanguages;
|
||||
}
|
||||
|
||||
|
||||
private String translateImpl(String query, String tl) {
|
||||
if (tkk == null) {
|
||||
initTkk();
|
||||
}
|
||||
if (tkk == null) {
|
||||
return null;
|
||||
}
|
||||
String tk = Utils.signWeb(query, tkk[0], tkk[1]);
|
||||
String url = "https://translate.google." + (NekoConfig.translationProvider == 2 ? "cn" : "com") + "/translate_a/single?client=webapp&dt=t&sl=auto" +
|
||||
"&tl=" + tl +
|
||||
"&tk=" + tk +
|
||||
"&q=" + Utils.encodeURIComponent(query); // 不能用URLEncoder
|
||||
String response = request(url);
|
||||
if (TextUtils.isEmpty(response)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return getResult(response);
|
||||
} catch (JSONException e) {
|
||||
FileLog.e(response + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getResult(String string) throws JSONException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
JSONArray array = new JSONArray(new JSONTokener(string)).getJSONArray(0);
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
sb.append(array.getJSONArray(i).getString(0));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void initTkk() {
|
||||
String response = request("https://translate.google." + (NekoConfig.translationProvider == 2 ? "cn" : "com"));
|
||||
if (TextUtils.isEmpty(response)) {
|
||||
FileLog.e("Tkk init failed");
|
||||
return;
|
||||
}
|
||||
tkk = matchTKK(response);
|
||||
if (tkk == null) {
|
||||
FileLog.e("Tkk init failed");
|
||||
}
|
||||
}
|
||||
|
||||
private long[] matchTKK(String src) {
|
||||
Matcher matcher = Pattern.compile("tkk\\s*[:=]\\s*['\"]([0-9]+)\\.([0-9]+)['\"]",
|
||||
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE).matcher(src);
|
||||
if (matcher.find()) {
|
||||
if (matcher.group(1) == null || matcher.group(2) == null) {
|
||||
return null;
|
||||
}
|
||||
//noinspection ConstantConditions
|
||||
return new long[]{Long.parseLong(matcher.group(1)), Long.parseLong(matcher.group(2))};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String request(String url) {
|
||||
try {
|
||||
ByteArrayOutputStream outbuf;
|
||||
InputStream httpConnectionStream;
|
||||
URL downloadUrl = new URL(url);
|
||||
URLConnection httpConnection = downloadUrl.openConnection();
|
||||
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1");
|
||||
httpConnection.setConnectTimeout(1000);
|
||||
httpConnection.setReadTimeout(2000);
|
||||
httpConnection.connect();
|
||||
httpConnectionStream = httpConnection.getInputStream();
|
||||
|
||||
outbuf = new ByteArrayOutputStream();
|
||||
|
||||
byte[] data = new byte[1024 * 32];
|
||||
while (true) {
|
||||
int read = httpConnectionStream.read(data);
|
||||
if (read > 0) {
|
||||
outbuf.write(data, 0, read);
|
||||
} else if (read == -1) {
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
String result = new String(outbuf.toByteArray());
|
||||
try {
|
||||
httpConnectionStream.close();
|
||||
} catch (Throwable e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
try {
|
||||
outbuf.close();
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable e) {
|
||||
FileLog.e(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
package tw.nekomimi.nekogram.translator;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import org.telegram.messenger.FileLog;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class LingoTranslator extends Translator {
|
||||
|
||||
private static LingoTranslator instance;
|
||||
private List<String> targetLanguages = Arrays.asList("zh", "en", "es", "fr", "ja", "ru");
|
||||
|
||||
static LingoTranslator getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (LingoTranslator.class) {
|
||||
if (instance == null) {
|
||||
instance = new LingoTranslator();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTargetLanguages() {
|
||||
return targetLanguages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String translate(String query, String tl) {
|
||||
LingoRequest params = new LingoRequest(query, "auto2" + tl);
|
||||
Gson gson = new Gson();
|
||||
String response = request(gson.toJson(params));
|
||||
if (TextUtils.isEmpty(response)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
LingoResponse lingoResponse = gson.fromJson(response, LingoResponse.class);
|
||||
if (TextUtils.isEmpty(lingoResponse.target)) {
|
||||
FileLog.e(response);
|
||||
return null;
|
||||
}
|
||||
return lingoResponse.target;
|
||||
} catch (Exception e) {
|
||||
FileLog.e(response + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String request(String param) {
|
||||
try {
|
||||
ByteArrayOutputStream outbuf;
|
||||
InputStream httpConnectionStream;
|
||||
URL downloadUrl = new URL("https://api.interpreter.caiyunai.com/v1/translator");
|
||||
HttpURLConnection httpConnection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
httpConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
httpConnection.addRequestProperty("X-Authorization", "token 9sdftiq37bnv410eon2l");//白嫖
|
||||
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1");
|
||||
httpConnection.setConnectTimeout(1000);
|
||||
httpConnection.setReadTimeout(2000);
|
||||
httpConnection.setRequestMethod("POST");
|
||||
httpConnection.setDoOutput(true);
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(httpConnection.getOutputStream());
|
||||
//noinspection CharsetObjectCanBeUsed
|
||||
byte[] t = param.getBytes("UTF-8");
|
||||
dataOutputStream.write(t);
|
||||
dataOutputStream.flush();
|
||||
dataOutputStream.close();
|
||||
httpConnection.connect();
|
||||
if (httpConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
httpConnectionStream = httpConnection.getErrorStream();
|
||||
} else {
|
||||
httpConnectionStream = httpConnection.getInputStream();
|
||||
}
|
||||
outbuf = new ByteArrayOutputStream();
|
||||
|
||||
byte[] data = new byte[1024 * 32];
|
||||
while (true) {
|
||||
int read = httpConnectionStream.read(data);
|
||||
if (read > 0) {
|
||||
outbuf.write(data, 0, read);
|
||||
} else if (read == -1) {
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
String result = new String(outbuf.toByteArray());
|
||||
try {
|
||||
httpConnectionStream.close();
|
||||
} catch (Throwable e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
try {
|
||||
outbuf.close();
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable e) {
|
||||
FileLog.e(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LingoRequest {
|
||||
|
||||
@SerializedName("source")
|
||||
@Expose
|
||||
@Keep
|
||||
public String source;
|
||||
@SerializedName("trans_type")
|
||||
@Expose
|
||||
@Keep
|
||||
String transType;
|
||||
@SerializedName("request_id")
|
||||
@Expose
|
||||
@Keep
|
||||
String requestId;
|
||||
@SerializedName("detect")
|
||||
@Expose
|
||||
@Keep
|
||||
Boolean detect;
|
||||
|
||||
LingoRequest(String source, String transType) {
|
||||
super();
|
||||
this.source = source;
|
||||
this.transType = transType;
|
||||
this.requestId = String.valueOf(System.currentTimeMillis());
|
||||
this.detect = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class LingoResponse {
|
||||
|
||||
@SerializedName("target")
|
||||
@Expose
|
||||
String target;
|
||||
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package tw.nekomimi.nekogram.translator;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.R;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import tw.nekomimi.nekogram.NekoConfig;
|
||||
|
||||
abstract public class Translator {
|
||||
|
||||
public static void translate(String query, TranslateCallBack translateCallBack) {
|
||||
Locale locale = LocaleController.getInstance().currentLocale;
|
||||
String toLang;
|
||||
if (NekoConfig.translationProvider != 3 && locale.getLanguage().equals("zh") && (locale.getCountry().toUpperCase().equals("CN") || locale.getCountry().toUpperCase().equals("TW"))) {
|
||||
toLang = locale.getLanguage() + "-" + locale.getCountry().toUpperCase();
|
||||
} else {
|
||||
toLang = locale.getLanguage();
|
||||
}
|
||||
Translator translator = NekoConfig.translationProvider == 3 ? LingoTranslator.getInstance() : GoogleWebTranslator.getInstance();
|
||||
if (!translator.getTargetLanguages().contains(toLang)) {
|
||||
translateCallBack.onUnsupported();
|
||||
} else {
|
||||
translator.startTask(query, toLang, translateCallBack);
|
||||
}
|
||||
}
|
||||
|
||||
public static String translateSync(String query) throws IOException {
|
||||
Locale locale = LocaleController.getInstance().currentLocale;
|
||||
String toLang;
|
||||
if (NekoConfig.translationProvider != 3 && locale.getLanguage().equals("zh") && (locale.getCountry().toUpperCase().equals("CN") || locale.getCountry().toUpperCase().equals("TW"))) {
|
||||
toLang = locale.getLanguage() + "-" + locale.getCountry().toUpperCase();
|
||||
} else {
|
||||
toLang = locale.getLanguage();
|
||||
}
|
||||
Translator translator = NekoConfig.translationProvider == 3 ? LingoTranslator.getInstance() : GoogleWebTranslator.getInstance();
|
||||
if (!translator.getTargetLanguages().contains(toLang)) {
|
||||
throw new IOException(LocaleController.getString("TranslateApiUnsupported", R.string.TranslateApiUnsupported));
|
||||
} else {
|
||||
try {
|
||||
String result = translator.translate(query, toLang);
|
||||
if (result == null) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
return result;
|
||||
} catch (Exception ex) {
|
||||
throw new IOException(LocaleController.getString("TranslateFailed", R.string.TranslateFailed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startTask(String query, String toLang, TranslateCallBack translateCallBack) {
|
||||
new MyAsyncTask().request(query, toLang, translateCallBack).execute();
|
||||
}
|
||||
|
||||
abstract protected String translate(String query, String tl);
|
||||
|
||||
abstract protected List<String> getTargetLanguages();
|
||||
|
||||
public interface TranslateCallBack {
|
||||
void onSuccess(String translation);
|
||||
|
||||
void onError();
|
||||
|
||||
void onUnsupported();
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private class MyAsyncTask extends AsyncTask<Void, Integer, String> {
|
||||
TranslateCallBack translateCallBack;
|
||||
String query;
|
||||
String tl;
|
||||
|
||||
public MyAsyncTask request(String query, String tl, TranslateCallBack translateCallBack) {
|
||||
this.query = query;
|
||||
this.tl = tl;
|
||||
this.translateCallBack = translateCallBack;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
return translate(query, tl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String result) {
|
||||
if (result == null) {
|
||||
translateCallBack.onError();
|
||||
} else {
|
||||
translateCallBack.onSuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package tw.nekomimi.nekogram.translator;
|
||||
package tw.nekomimi.nekogram.transtale;
|
||||
|
||||
import org.dizitart.no2.Document;
|
||||
import org.dizitart.no2.IndexType;
|
|
@ -1,4 +1,4 @@
|
|||
package tw.nekomimi.nekogram.translator;
|
||||
package tw.nekomimi.nekogram.transtale;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
|
@ -7,9 +7,9 @@ import java.util.List;
|
|||
/**
|
||||
* @author Bin
|
||||
*/
|
||||
class Utils {
|
||||
public class TransUtils {
|
||||
|
||||
static String signWeb(String text, long key1, long key2) {
|
||||
public static String signWeb(String text, long key1, long key2) {
|
||||
List<Integer> c = new ArrayList<>();
|
||||
for (int F = 0; F < text.length(); F++) {
|
||||
int p = text.charAt(F);
|
||||
|
@ -56,7 +56,7 @@ class Utils {
|
|||
return r;
|
||||
}
|
||||
|
||||
static String encodeURIComponent(String str) {
|
||||
public static String encodeURIComponent(String str) {
|
||||
if (str == null) return null;
|
||||
|
||||
byte[] bytes = str.getBytes(Charset.defaultCharset());
|
|
@ -1,4 +1,4 @@
|
|||
package tw.nekomimi.nekogram.translator;
|
||||
package tw.nekomimi.nekogram.transtale;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
|
@ -62,7 +62,7 @@ public class TranslateBottomSheet extends BottomSheet {
|
|||
url = String.format("https://translate.google.cn/?view=home&op=translate&text=%s", URLEncoder.encode(text, "UTF-8"));
|
||||
break;
|
||||
case -3:
|
||||
url = String.format("https://fanyi.baidu.com/?aldtype=38319&tpltype=sigma#auto/zh/%s", Utils.encodeURIComponent(text));
|
||||
url = String.format("https://fanyi.baidu.com/?aldtype=38319&tpltype=sigma#auto/zh/%s", TransUtils.encodeURIComponent(text));
|
||||
break;
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
|
@ -1,18 +1,18 @@
|
|||
package tw.nekomimi.nekogram.translator
|
||||
package tw.nekomimi.nekogram.transtale
|
||||
|
||||
import org.dizitart.no2.filters.Filters
|
||||
import org.dizitart.no2.objects.filters.ObjectFilters
|
||||
import tw.nekomimi.nekogram.database.mkCacheDatabase
|
||||
|
||||
object TranslateDb {
|
||||
|
||||
val db = mkCacheDatabase("translate_caches")
|
||||
var conn = db.getRepository("trans",TransItem::class.java)
|
||||
var conn = db.getRepository("trans", TransItem::class.java)
|
||||
|
||||
@JvmStatic
|
||||
fun clear() {
|
||||
|
||||
conn.drop()
|
||||
conn = db.getRepository("trans",TransItem::class.java)
|
||||
conn.remove(ObjectFilters.ALL)
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package tw.nekomimi.nekogram.transtale
|
||||
|
||||
import org.telegram.messenger.FileLog
|
||||
import org.telegram.messenger.LocaleController
|
||||
import tw.nekomimi.nekogram.NekoConfig
|
||||
import tw.nekomimi.nekogram.transtale.source.*
|
||||
import tw.nekomimi.nekogram.utils.UIUtil
|
||||
import java.util.*
|
||||
|
||||
interface Translator {
|
||||
|
||||
fun doTranslate(from: String, to: String, query: String): String
|
||||
|
||||
companion object {
|
||||
|
||||
@Throws(Exception::class)
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun translate(to: Locale = LocaleController.getInstance().currentLocale, query: String): String {
|
||||
|
||||
var toLang = to.language
|
||||
|
||||
if (NekoConfig.translationProvider < 3) {
|
||||
|
||||
if (to.language == "zh" && (to.country.toUpperCase() == "CN" || to.country.toUpperCase() == "TW")) {
|
||||
toLang = to.language + "-" + to.country.toUpperCase()
|
||||
} else if (to.language == "pt" && to.country in arrayOf("PT","BR")) {
|
||||
toLang = to.language + "-" + to.country.toUpperCase()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val translator = when (NekoConfig.translationProvider) {
|
||||
in 1..2 -> GoogleWebTranslator
|
||||
3 -> LingoTranslator
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
// FileLog.d("[Trans] use provider ${translator.javaClass.simpleName}, toLang: $toLang, query: $query")
|
||||
|
||||
return translator.doTranslate("auto", toLang, query)
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun translate(to: Locale = LocaleController.getInstance().currentLocale, query: String, translateCallBack: TranslateCallBack) {
|
||||
|
||||
UIUtil.runOnIoDispatcher(Runnable {
|
||||
|
||||
runCatching {
|
||||
|
||||
val result = translate(to, query)
|
||||
|
||||
UIUtil.runOnUIThread(Runnable {
|
||||
|
||||
translateCallBack.onSuccess(result)
|
||||
|
||||
})
|
||||
|
||||
}.onFailure {
|
||||
|
||||
translateCallBack.onFailed(it is UnsupportedOperationException, it.message ?: it.javaClass.simpleName)
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
interface TranslateCallBack {
|
||||
|
||||
fun onSuccess(translation: String)
|
||||
fun onFailed(unsupported: Boolean, message: String)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package tw.nekomimi.nekogram.transtale.source
|
||||
|
||||
import android.text.TextUtils
|
||||
import okhttp3.Request
|
||||
import org.telegram.messenger.LocaleController
|
||||
import org.telegram.messenger.R
|
||||
import tw.nekomimi.nekogram.NekoConfig
|
||||
import tw.nekomimi.nekogram.transtale.TransUtils
|
||||
import tw.nekomimi.nekogram.transtale.Translator
|
||||
import tw.nekomimi.nekogram.utils.HttpUtil
|
||||
import tw.nekomimi.nekogram.utils.applyUserAgent
|
||||
import java.lang.UnsupportedOperationException
|
||||
import java.util.regex.Pattern
|
||||
|
||||
object GoogleWebTranslator : Translator {
|
||||
|
||||
lateinit var tkk: LongArray
|
||||
|
||||
override fun doTranslate(from: String, to: String, query: String): String {
|
||||
|
||||
if (to !in targetLanguages) {
|
||||
|
||||
throw UnsupportedOperationException(LocaleController.getString("TranslateApiUnsupported", R.string.TranslateApiUnsupported))
|
||||
|
||||
}
|
||||
|
||||
if (!GoogleWebTranslator::tkk.isInitialized) {
|
||||
|
||||
val response = HttpUtil.get("https://translate.google." + if (NekoConfig.translationProvider == 2) "cn" else "com")
|
||||
|
||||
if (TextUtils.isEmpty(response)) {
|
||||
|
||||
error("Tkk init failed")
|
||||
|
||||
}
|
||||
|
||||
val matcher = Pattern.compile("tkk\\s*[:=]\\s*['\"]([0-9]+)\\.([0-9]+)['\"]", Pattern.CASE_INSENSITIVE or Pattern.UNICODE_CASE).matcher(response)
|
||||
|
||||
tkk = if (matcher.find() && matcher.group(1) != null && matcher.group(2) != null) {
|
||||
longArrayOf(matcher.group(1).toLong(), matcher.group(2).toLong())
|
||||
} else error("Tkk match failed")
|
||||
|
||||
}
|
||||
|
||||
val tk = TransUtils.signWeb(query, tkk[0], tkk[1])
|
||||
|
||||
val url = "https://translate.google." + (if (NekoConfig.translationProvider == 2) "cn" else "com") + "/translate_a/single?client=webapp&dt=t&sl=auto" +
|
||||
"&tl=" + to +
|
||||
"&tk=" + tk +
|
||||
"&q=" + TransUtils.encodeURIComponent(query) // 不能用URLEncoder
|
||||
|
||||
val response = HttpUtil.okHttpClient
|
||||
.newCall(Request.Builder()
|
||||
.url(url)
|
||||
.applyUserAgent()
|
||||
.build()).execute()
|
||||
|
||||
if (response.code != 200) {
|
||||
|
||||
error("HTTP ${response.code} : ${response.body?.string()}")
|
||||
|
||||
}
|
||||
|
||||
return response.body!!.string()
|
||||
|
||||
}
|
||||
|
||||
private val targetLanguages = listOf(
|
||||
"sq", "ar", "am", "az", "ga", "et", "eu", "be", "bg", "is", "pl", "bs", "fa",
|
||||
"af", "da", "de", "ru", "fr", "tl", "fi", "fy", "km", "ka", "gu", "kk", "ht",
|
||||
"ko", "ha", "nl", "ky", "gl", "ca", "cs", "kn", "co", "hr", "ku", "la", "lv",
|
||||
"lo", "lt", "lb", "ro", "mg", "mt", "mr", "ml", "ms", "mk", "mi", "mn", "bn",
|
||||
"my", "hmn", "xh", "zu", "ne", "no", "pa", "pt", "ps", "ny", "ja", "sv", "sm",
|
||||
"sr", "st", "si", "eo", "sk", "sl", "sw", "gd", "ceb", "so", "tg", "te", "ta",
|
||||
"th", "tr", "cy", "ur", "uk", "uz", "es", "iw", "el", "haw", "sd", "hu", "sn",
|
||||
"hy", "ig", "it", "yi", "hi", "su", "id", "jw", "en", "yo", "vi", "zh-TW", "zh-CN", "zh")
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package tw.nekomimi.nekogram.transtale.source
|
||||
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONObject
|
||||
import org.telegram.messenger.LocaleController
|
||||
import org.telegram.messenger.R
|
||||
import tw.nekomimi.nekogram.transtale.Translator
|
||||
import tw.nekomimi.nekogram.utils.HttpUtil
|
||||
import tw.nekomimi.nekogram.utils.applyUserAgent
|
||||
|
||||
object LingoTranslator : Translator {
|
||||
|
||||
override fun doTranslate(from: String, to: String, query: String): String {
|
||||
|
||||
if (to !in listOf("zh", "en", "es", "fr", "ja", "ru")) {
|
||||
|
||||
error(LocaleController.getString("TranslateApiUnsupported", R.string.TranslateApiUnsupported))
|
||||
|
||||
}
|
||||
|
||||
val response = HttpUtil.okHttpClient.newCall(Request.Builder()
|
||||
.url("https://api.interpreter.caiyunai.com/v1/translator")
|
||||
.header("Content-Type", "application/json; charset=UTF-8")
|
||||
.header("X-Authorization", "token 9sdftiq37bnv410eon2l") // 白嫖
|
||||
.applyUserAgent()
|
||||
.post(JSONObject().apply {
|
||||
|
||||
put("source", query)
|
||||
put("trans_type", "${from}2$to")
|
||||
put("request_id", System.currentTimeMillis().toString())
|
||||
put("detect", true)
|
||||
|
||||
}.toString().toRequestBody()).build()).execute()
|
||||
|
||||
if (response.code != 200) {
|
||||
|
||||
error("HTTP ${response.code} : ${response.body?.string()}")
|
||||
|
||||
}
|
||||
|
||||
return JSONObject(response.body!!.string()).getString("target")
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,8 @@ import org.telegram.messenger.LocaleController
|
|||
import org.telegram.messenger.R
|
||||
import org.telegram.ui.ActionBar.AlertDialog
|
||||
import org.telegram.ui.ActionBar.Theme
|
||||
import tw.nekomimi.nekogram.NekoConfig
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
object AlertUtil {
|
||||
|
||||
|
@ -58,4 +60,78 @@ object AlertUtil {
|
|||
|
||||
})
|
||||
|
||||
@JvmStatic
|
||||
fun showTransFailedDialog(ctx: Context, noRetry: Boolean, message: String, retryRunnable: Runnable) = UIUtil.runOnUIThread(Runnable {
|
||||
|
||||
ctx.setTheme(R.style.Theme_TMessages)
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(LocaleController.getString("TranslateFailed", R.string.TranslateFailed))
|
||||
|
||||
builder.setMessage(message)
|
||||
|
||||
val reference = AtomicReference<AlertDialog>()
|
||||
|
||||
builder.setNeutralButton(LocaleController.getString("ChangeTranslateProvider", R.string.ChangeTranslateProvider)) {
|
||||
|
||||
_, _ ->
|
||||
|
||||
val view = reference.get().getButton(AlertDialog.BUTTON_NEUTRAL)
|
||||
|
||||
val popup = PopupBuilder(view, true)
|
||||
|
||||
popup.setItems(arrayOf(
|
||||
LocaleController.getString("ProviderGoogleTranslate", R.string.ProviderGoogleTranslate),
|
||||
LocaleController.getString("ProviderGoogleTranslateCN", R.string.ProviderGoogleTranslateCN),
|
||||
LocaleController.getString("ProviderLingocloud", R.string.ProviderLingocloud)
|
||||
)) { item, _ ->
|
||||
|
||||
reference.get().dismiss()
|
||||
|
||||
NekoConfig.setTranslationProvider(item + 1)
|
||||
|
||||
retryRunnable.run()
|
||||
|
||||
}
|
||||
|
||||
popup.show()
|
||||
|
||||
}
|
||||
|
||||
if (noRetry) {
|
||||
|
||||
builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel)) { _, _ ->
|
||||
|
||||
reference.get().dismiss()
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
builder.setPositiveButton(LocaleController.getString("Retry", R.string.Retry)) { _, _ ->
|
||||
|
||||
reference.get().dismiss()
|
||||
|
||||
retryRunnable.run()
|
||||
|
||||
}
|
||||
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel)) { _, _ ->
|
||||
|
||||
reference.get().dismiss()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
reference.set(builder.create().apply {
|
||||
|
||||
setDismissDialogByButtons(false)
|
||||
show()
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
}
|
|
@ -33,7 +33,7 @@ open class DnsFactory {
|
|||
fun addProvider(url: String) {
|
||||
|
||||
providers.add(DnsOverHttps.Builder()
|
||||
.client(HttpUtil.okhttpClient)
|
||||
.client(HttpUtil.okHttpClient)
|
||||
.url(url.toHttpUrl())
|
||||
.includeIPv6(ConnectionsManager.useIpv6Address())
|
||||
.build())
|
||||
|
|
|
@ -7,34 +7,46 @@ import java.net.InetSocketAddress
|
|||
import java.net.Proxy
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
fun Request.Builder.applyUserAgent(): Request.Builder {
|
||||
|
||||
header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1")
|
||||
header("X-Requested-With", "XMLHttpRequest")
|
||||
|
||||
return this
|
||||
|
||||
}
|
||||
|
||||
object HttpUtil {
|
||||
|
||||
@JvmField
|
||||
val okhttpClient = OkHttpClient().newBuilder().readTimeout(500,TimeUnit.MILLISECONDS).build()
|
||||
val okHttpClient = OkHttpClient().newBuilder().connectTimeout(5, TimeUnit.SECONDS).build()
|
||||
|
||||
@JvmStatic
|
||||
val okhttpClientWithCurrProxy: OkHttpClient get() {
|
||||
val okHttpClientWithCurrProxy: OkHttpClient
|
||||
get() {
|
||||
|
||||
return if (!SharedConfig.proxyEnabled || SharedConfig.currentProxy?.secret != null ) {
|
||||
return if (!SharedConfig.proxyEnabled || SharedConfig.currentProxy?.secret != null) {
|
||||
|
||||
okhttpClient
|
||||
okHttpClient
|
||||
|
||||
} else {
|
||||
} else {
|
||||
|
||||
okhttpClient.newBuilder()
|
||||
.proxy(Proxy(Proxy.Type.SOCKS,InetSocketAddress(SharedConfig.currentProxy.address,SharedConfig.currentProxy.port)))
|
||||
.build()
|
||||
okHttpClient.newBuilder()
|
||||
.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress(SharedConfig.currentProxy.address, SharedConfig.currentProxy.port)))
|
||||
.build()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun get(url: String): String {
|
||||
|
||||
val request = Request.Builder().url(url).build()
|
||||
val request = Request.Builder().url(url)
|
||||
.applyUserAgent()
|
||||
.build()
|
||||
|
||||
okhttpClient.newCall(request).execute().apply {
|
||||
okHttpClient.newCall(request).execute().apply {
|
||||
|
||||
val body = body
|
||||
|
||||
|
@ -44,25 +56,15 @@ object HttpUtil {
|
|||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun get(url: String,ua: String): String {
|
||||
|
||||
val request = Request.Builder().url(url).addHeader("User-Agent",ua).build()
|
||||
|
||||
okhttpClient.newCall(request).execute().apply {
|
||||
|
||||
return body?.string() ?: error("HTTP ERROR $code")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getByteArray(url: String): ByteArray {
|
||||
|
||||
val request = Request.Builder().url(url).build()
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.applyUserAgent()
|
||||
.build()
|
||||
|
||||
okhttpClient.newCall(request).execute().apply {
|
||||
okHttpClient.newCall(request).execute().apply {
|
||||
|
||||
return body?.bytes() ?: error("HTTP ERROR $code")
|
||||
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import org.telegram.ui.ActionBar.ActionBarMenuItem
|
||||
import org.telegram.ui.ActionBar.Theme
|
||||
|
||||
class PopupBuilder(anchor: View) : ActionBarMenuItem(anchor.context, null, Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, -0x4c4c4d) {
|
||||
@SuppressLint("ViewConstructor")
|
||||
class PopupBuilder @JvmOverloads constructor(anchor: View, dialog: Boolean = false) : ActionBarMenuItem(anchor.context, null, Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, -0x4c4c4d) {
|
||||
|
||||
init {
|
||||
|
||||
setAnchor(anchor)
|
||||
|
||||
isShowOnTop = dialog
|
||||
|
||||
isVerticalScrollBarEnabled = true
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface ItemListener {
|
||||
|
||||
fun onClick(item: CharSequence)
|
||||
|
||||
}
|
||||
|
||||
fun setItems(items: Array<CharSequence>, listener: ItemListener) {
|
||||
fun setItems(items: Array<CharSequence>, listener: (Int,CharSequence) -> Unit) {
|
||||
|
||||
removeAllSubItems()
|
||||
|
||||
|
@ -33,32 +30,7 @@ class PopupBuilder(anchor: View) : ActionBarMenuItem(anchor.context, null, Theme
|
|||
|
||||
setDelegate {
|
||||
|
||||
listener.onClick(items[it])
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface IndexedItemListener {
|
||||
|
||||
fun onClick(item: Int)
|
||||
|
||||
}
|
||||
|
||||
fun setItemsIndexed(items: Array<CharSequence>, listener: IndexedItemListener) {
|
||||
|
||||
removeAllSubItems()
|
||||
|
||||
items.forEachIndexed { i, v ->
|
||||
|
||||
addSubItem(i, v)
|
||||
|
||||
}
|
||||
|
||||
setDelegate {
|
||||
|
||||
listener.onClick(it)
|
||||
listener(it,items[it])
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="PrivacyNotice">هشدار حریم خصوصی</string>
|
||||
<string name="PrivacyNoticePhoneVisible">تشخیص داده شده است که شماره تلفن همراه شما برای همه قابل رویت است ، و این ممکن است باعث شود هکرهای تحت کنترل دولت هویت واقعی شما را پیدا کنند ، لطفا آن را خاموش کنید!</string>
|
||||
<string name="ApplySuggestion">قبول،اعمال کن</string>
|
||||
<string name="DoNotRemindAgain">دوباره یادآوری نکن</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,13 +1,113 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="NekoXProxy">پروکسی عمومی نکوX</string>
|
||||
<string name="PublicPrefix">(عمومی)</string>
|
||||
<string name="NekoXProxyInfo">ممکن است ده ها ثانیه برای بارگیری پروکسی داخلی نکوX طول بکشد</string>
|
||||
<string name="UseOfficalId">پنهان شده به عنوان برنامه رسمی</string>
|
||||
<string name="UseOfficalIdNotice">با استفاده از شناسه رسمی برنامه وارد شوید ، اگر قادر به ثبت نام یا ورود به سیستم نیستید ، این ممکن است کمک کند. \ n \ n توجه: اگر از آخرین نسخه استفاده می کنید ، fcm کار نخواهد کرد.</string>
|
||||
<string name="ChangeTranslateProvider">تغییر ارائه دهنده خدمات</string>
|
||||
<string name="PrivacyNotice">هشدار حریم خصوصی</string>
|
||||
<string name="PrivacyNoticePhoneVisible">تشخیص داده شده است که شماره تلفن همراه شما برای همه قابل رویت است ، و این ممکن است باعث شود هکرهای تحت کنترل دولت هویت واقعی شما را پیدا کنند ، لطفا آن را خاموش کنید!</string>
|
||||
<string name="PrivacyNoticeAddByPhone">تشخیص داده شده است که تنظیمات \" یافتن من از طریق شماره تلفن\" شما خاموش نیست، که ممکن است باعث شود یک هکر تحت کنترل دولت بتواند هویت واقعی شما را پیدا کند ، لطفاً آن را خاموش کنید!</string>
|
||||
<string name="PrivacyNoticeP2p">تشخیص داده شده است که تنظیمات \"مجاز تماس های نظیر به نظیر\" را خاموش نکرده اید ، که ممکن است باعث شود هکرهای تحت کنترل دولت هویت واقعی شما را پیدا کنند ، لطفاً آن را خاموش کنید!</string>
|
||||
<string name="ApplySuggestion">قبول،اعمال کن</string>
|
||||
<string name="DoNotRemindAgain">دیگر یادآوری نشود</string>
|
||||
<string name="RemoveTitleEmoji">حذف ایموجی کنار اسم Nekogram x</string>
|
||||
<string name="NekoXProxy">پروکسی عمومی NekoX</string>
|
||||
<string name="PublicPrefix">[عمومی]</string>
|
||||
<string name="NekoXProxyInfo">ممکن است چند ثانیه برای بارگیری پروکسی داخلی NekoX طول بکشد :)</string>
|
||||
<string name="HidePublicProxyList">مخفی کردن لیست پروکسی عمومی</string>
|
||||
<string name="DisableChatAction">وضعیت مرا ارسال نکن</string>
|
||||
<string name="FakeScreenshot">تصویر قبل</string>
|
||||
<string name="EnableDeveloperMode">فعالسازی توسعه دهنده</string>
|
||||
<string name="DisableDeveloperMode">غیرفعالسازی مد توسعه دهنده</string>
|
||||
<string name="FakeScreenshot">تصویر پیشنمایش</string>
|
||||
<string name="SaveCacheToSdcard">ذخیره کش در حافظه sd card</string>
|
||||
<string name="FilterNameUsers">کاربران</string>
|
||||
<string name="FilterNameUsersDescription">فقط پیام های چت های خصوصی</string>
|
||||
<string name="FilterNameContacts">مخاطبین</string>
|
||||
<string name="FilterNameContactsDescription">فقط پیام های کاربران ذخیره شده</string>
|
||||
<string name="FilterNameGroups">گروه ها</string>
|
||||
<string name="FilterNameGroupsDescription">فقط پیامهای گفتگو های گروهی</string>
|
||||
<string name="FilterNameChannels">کانال ها</string>
|
||||
<string name="FilterNameChannelsDescription">فقط پیام های کانال ها</string>
|
||||
<string name="FilterNameBots">ربات ها</string>
|
||||
<string name="FilterNameBotsDescription">فقط پیام های ربات ها</string>
|
||||
<string name="FilterNameUnmuted">صدا دار</string>
|
||||
<string name="FilterNameUnmutedDescription">فقط پیام های گفتگو های صدا دار</string>
|
||||
<string name="FilterNameUnread2">خوانده نشده</string>
|
||||
<string name="FilterNameUnreadDescription">فقط پیام های خوانده نشده</string>
|
||||
<string name="FilterNameUnmutedAndUnread">صدا دار& خوانده نشده</string>
|
||||
<string name="FilterNameUnmutedAndUnreadDescription">فقط پیام های خوانده نشده از گفتگو های صدادار</string>
|
||||
<string name="IgnoreMutedCount">نمایش ندادن شمارشگر چت های خوانده نشده در پوشه ی تب ها</string>
|
||||
<string name="DialogsSettings">تنظیمات گفتگو</string>
|
||||
<string name="SortMenu">تنظیمات مرتب سازی گفتگو</string>
|
||||
<string name="SortByUnread">ترتیب بر اساس خوانده نشده</string>
|
||||
<string name="SortByUnmuted">ترتیب بر اساس صدادار</string>
|
||||
<string name="SortByUser">ترتیب بر اساس کاربر</string>
|
||||
<string name="SortByContacts">ترتیب بر اساس مخاطبین</string>
|
||||
<string name="NekoXPushService">خدمات NekoX</string>
|
||||
<string name="EnablePushAlert">لطفا خدمات NekoX را فعال کنید</string>
|
||||
<string name="DisablePushAlert">لطفا خدمات NekoX رو غیرفعل کنید</string>
|
||||
<string name="MIUIPermissionNote">برای کاربران MIUI،لطفا دسترسی شروع خودکار را برای دریافت اعلانات NekoX فعال کنید.</string>
|
||||
<string name="DisableUndo">غیرفعال کردن واگرد</string>
|
||||
<string name="DisableSystemAccount">غیرفعال کردن حساب کاربری سیستم</string>
|
||||
<string name="FilterMenu">منوی فیلتر گفتگو ها</string>
|
||||
<string name="DisableProxyWhenVpnEnabled">غیرفعال کردن پروکسی هنگام فعال کردن VPN</string>
|
||||
<string name="SkipOpenLinkConfirm">غیرفعال کردن کادر تایید باز شدن لینک</string>
|
||||
<string name="DeleteAllInChat">حذف همه در این گفتگو</string>
|
||||
<string name="DeleteAllInChatAlert">هشدار! با این کار ، **تمام پیام ها** در این گفتگو برای همه شرکت کنندگان حذف می شود.</string>
|
||||
<string name="UnblockAll">رفع مسدودی همه</string>
|
||||
<string name="UnblockAllWarn">آیا شما از رفع مسدود**همه ی کاربران و ربات ها**اطمینان دارید؟</string>
|
||||
<string name="BlockedListEmpty">شما هیچ فردی را مسدود نکرده اید :)</string>
|
||||
<string name="ProxyTypeVmess">پروکسی Vmess</string>
|
||||
<string name="AddProxySocks5">افزودن پروکسی Socks5</string>
|
||||
<string name="AddProxyTelegram">افزودن پروکسی MTproto</string>
|
||||
<string name="AddProxyVmess">افزودن پروکسی Vmess</string>
|
||||
<string name="AddProxySS">افزودن شادوساکس SS</string>
|
||||
<string name="AddProxySSR">افزودن شادوساکس SSR</string>
|
||||
<string name="EditProxy">ویرایش پروکسی</string>
|
||||
<string name="ShareProxy">اشتراک گذاری پروکسی</string>
|
||||
<string name="ProxyDelete">حذف پروکسی</string>
|
||||
<string name="ProxyInfoVmess">تنظیمات پروکسی Vmess</string>
|
||||
<string name="VmessUserId">آیدی کاربر</string>
|
||||
<string name="VmessAlterId">آیدی عددی</string>
|
||||
<string name="VmessSecurity">Security</string>
|
||||
<string name="VmessNetwork">Network</string>
|
||||
<string name="VmessHeadType">Head Type</string>
|
||||
<string name="VmessRequestHost">Request Host / QUIC Security</string>
|
||||
<string name="VmessPath">Path / QUIC Key</string>
|
||||
<string name="VmessTls">Use TLS</string>
|
||||
<string name="ProxyInfoSS">تنظیمات شادوساکس SS</string>
|
||||
<string name="SSPassword">گذرواژه</string>
|
||||
<string name="SSMethod">Encrypt Method</string>
|
||||
<string name="ProxyInfoSSR">تنظیمات پروکسی شادوساکس SSR</string>
|
||||
<string name="SSRProtocol">Protocol</string>
|
||||
<string name="SSRProtocolParams">Protocol Params</string>
|
||||
<string name="SSRObfs">Obfs</string>
|
||||
<string name="SSRObfsParam">Obfs Param</string>
|
||||
<string name="ProxyRemarks">ملاحظات</string>
|
||||
<string name="RetestPing">تست مجدد پینگ تمامی سرورها</string>
|
||||
<string name="ReorderByPing">مرتب سازی پروکسی ها براساس پینگ</string>
|
||||
<string name="ExportProxies">اکسپورت سرورها بصورت فایل</string>
|
||||
<string name="ImportProxies">ایمپورت فایل سرورها</string>
|
||||
<string name="ImportProxyList">ایمپورت سرورهای پروکسی</string>
|
||||
<string name="ImportProxyListConfirm">آیا شما از**حذف تمامی سرور ها**اطمینان دارید؟</string>
|
||||
<string name="InvalidProxyFile">لیست پروکسی نامعتبر: </string>
|
||||
<string name="ImportedProxies">سرور های پروکسی واردشده: </string>
|
||||
<string name="ErrorsInImport">مشکل در وارد کردن فایل: </string>
|
||||
<string name="NoProxy">شما هیچ سرور پروکسی اضافه نکرده اید.</string>
|
||||
<string name="DeleteAllServer">حذف تمامی سرور ها</string>
|
||||
<string name="DeleteUnavailableServer">حذف سرور های غیرقابل دسترس</string>
|
||||
<string name="DeleteAllServerConfirm">آیا شما از**حذف تمامی سرور ها**اطمینان دارید؟</string>
|
||||
<string name="DeleteUnavailableServerConfirm">آیا شما از**حذف تمامی سرور های غیرقابل دسترس**اطمینان دارید؟</string>
|
||||
<string name="MinApi21Required">متأسفیم ، حداقل به Android 5 نیاز دارید.</string>
|
||||
<string name="ImportProxyFromClipboard">وارد کردن از کلیپ بورد</string>
|
||||
<string name="BrokenLink">لینک خراب/ناشناس</string>
|
||||
<string name="ShareQRCode">کد QR</string>
|
||||
<string name="ScanQRCode">اسکن کد QR</string>
|
||||
<string name="NoQrFound">هیچ کد QR یافت نشد</string>
|
||||
<string name="EnableDeveloperMode">فعالسازی حالت توسعه دهنده</string>
|
||||
<string name="DisableDeveloperMode">غیرفعالسازی حالت توسعه دهنده</string>
|
||||
<string name="DeveloperSettings">تنظیمات توسعه دهنده</string>
|
||||
<string name="DisableFlagSecure">غیرفعالسازی پرچم امنیتی</string>
|
||||
<string name="DisableScreenshotDetection">عدم شناسایی اسکرینشات</string>
|
||||
<string name="DisableScreenshotDetection">غیر فعال کردن شناسایی اسکرینشات</string>
|
||||
<string name="LoginSettings">تنظیمات ورود به سیستم</string>
|
||||
<string name="ShowTestBackend">نمایش آزمایشی پس زمینه</string>
|
||||
<string name="ShowBotLogin">دیدن ربات وارد شده</string>
|
||||
<string name="NekoXFaq">پرسش های متداول NekoX</string>
|
||||
</resources>
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
<string name="UseOfficalId">Disguised as official app</string>
|
||||
<string name="UseOfficalIdNotice">Log in using the official App Id, if you are unable to register or log in, this may help.\n\nNote: fcm will not work if you are using the release version.</string>
|
||||
|
||||
<string name="ChangeTranslateProvider">Change Provider</string>
|
||||
|
||||
<string name="PrivacyNotice">Privacy warning</string>
|
||||
<string name="PrivacyNoticePhoneVisible">It is detected that your mobile phone number is visible to anyone, which may cause government-controlled hackers to find your true identity, please turn it off!</string>
|
||||
<string name="PrivacyNoticeAddByPhone">It is detected that you are not turned off the \"Allow find me through phone number\" Setting, which may cause a government-controlled hacker to find your true identity, please turn it off!</string>
|
||||
|
|
Loading…
Reference in New Issue