Merge branch 'master' into v2.4

This commit is contained in:
Mygod
2019-04-14 10:27:46 +08:00
12 changed files with 84 additions and 85 deletions

View File

@@ -3,7 +3,7 @@
apply plugin: 'com.github.ben-manes.versions' apply plugin: 'com.github.ben-manes.versions'
buildscript { buildscript {
ext.kotlinVersion = '1.3.21' ext.kotlinVersion = '1.3.30'
repositories { repositories {
google() google()
jcenter() jcenter()

Binary file not shown.

View File

@@ -1,6 +1,5 @@
#Wed Jan 03 07:06:26 CST 2018
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip

68
gradlew vendored
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env sh
############################################################################## ##############################################################################
## ##
@@ -6,12 +6,30 @@
## ##
############################################################################## ##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Attempt to set APP_HOME
DEFAULT_JVM_OPTS="" # 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_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"
@@ -30,6 +48,7 @@ die ( ) {
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false
case "`uname`" in case "`uname`" in
CYGWIN* ) CYGWIN* )
cygwin=true cygwin=true
@@ -40,26 +59,11 @@ case "`uname`" in
MINGW* ) MINGW* )
msys=true msys=true
;; ;;
NONSTOP* )
nonstop=true
;;
esac esac
# 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
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
@@ -85,7 +89,7 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n` MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -150,11 +154,19 @@ if $cygwin ; then
esac esac
fi fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules # Escape application args
function splitJvmOpts() { save () {
JVM_OPTS=("$@") for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
} }
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS APP_ARGS=$(save "$@")
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" # 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" "$@"

14
gradlew.bat vendored
View File

@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
@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=
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% 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 @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail goto fail
:init :init
@rem Get command-line arguments, handling Windowz variants @rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args :win9xME_args
@rem Slurp the command line arguments. @rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%* set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute :execute
@rem Setup the command line @rem Setup the command line

View File

@@ -42,6 +42,7 @@ android {
} }
dataBinding.enabled = true dataBinding.enabled = true
flavorDimensions("freedom") flavorDimensions("freedom")
packagingOptions.exclude 'META-INF/*.kotlin_module'
productFlavors { productFlavors {
fdroid { fdroid {
dimension "freedom" dimension "freedom"
@@ -82,14 +83,14 @@ dependencies {
implementation "androidx.room:room-ktx:$roomVersion" implementation "androidx.room:room-ktx:$roomVersion"
implementation 'com.android.billingclient:billing:1.2.2' implementation 'com.android.billingclient:billing:1.2.2'
implementation 'com.github.luongvo:BadgeView:1.1.5' implementation 'com.github.luongvo:BadgeView:1.1.5'
implementation 'com.github.topjohnwu.libsu:core:2.3.3' implementation 'com.github.topjohnwu.libsu:core:2.4.0'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
implementation 'com.jakewharton.timber:timber:4.7.1' implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.linkedin.dexmaker:dexmaker:2.25.0' implementation 'com.linkedin.dexmaker:dexmaker:2.25.0'
implementation 'com.takisoft.preferencex:preferencex-simplemenu:1.0.0' implementation 'com.takisoft.preferencex:preferencex-simplemenu:1.0.0'
implementation 'net.glxn.qrgen:android:2.0' implementation 'net.glxn.qrgen:android:2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.0'
for (dep in aux) { for (dep in aux) {
freedomImplementation dep freedomImplementation dep
googleImplementation dep googleImplementation dep

View File

@@ -3,5 +3,5 @@
<issue id="InvalidPackage"> <issue id="InvalidPackage">
<ignore regexp="org.mockito.*" /> <ignore regexp="org.mockito.*" />
</issue> </issue>
<issue id="MissingTranslation" severity="informational" /> <issue id="MissingTranslation" severity="ignore" />
</lint> </lint>

View File

@@ -36,18 +36,15 @@ import be.mygod.vpnhotspot.room.AppDatabase
import be.mygod.vpnhotspot.room.ClientStats import be.mygod.vpnhotspot.room.ClientStats
import be.mygod.vpnhotspot.room.TrafficRecord import be.mygod.vpnhotspot.room.TrafficRecord
import be.mygod.vpnhotspot.room.macToString import be.mygod.vpnhotspot.room.macToString
import be.mygod.vpnhotspot.util.MainScope
import be.mygod.vpnhotspot.util.SpanFormatter import be.mygod.vpnhotspot.util.SpanFormatter
import be.mygod.vpnhotspot.util.computeIfAbsentCompat import be.mygod.vpnhotspot.util.computeIfAbsentCompat
import be.mygod.vpnhotspot.util.toPluralInt import be.mygod.vpnhotspot.util.toPluralInt
import be.mygod.vpnhotspot.widget.SmartSnackbar import be.mygod.vpnhotspot.widget.SmartSnackbar
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.text.NumberFormat import java.text.NumberFormat
class ClientsFragment : Fragment(), MainScope by MainScope.Supervisor() { class ClientsFragment : Fragment() {
@Parcelize @Parcelize
data class NicknameArg(val mac: Long, val nickname: CharSequence) : Parcelable data class NicknameArg(val mac: Long, val nickname: CharSequence) : Parcelable
class NicknameDialogFragment : AlertDialogFragment<NicknameArg, Empty>() { class NicknameDialogFragment : AlertDialogFragment<NicknameArg, Empty>() {
@@ -140,7 +137,9 @@ class ClientsFragment : Fragment(), MainScope by MainScope.Supervisor() {
val wasWorking = TrafficRecorder.isWorking(client.mac) val wasWorking = TrafficRecorder.isWorking(client.mac)
client.obtainRecord().apply { client.obtainRecord().apply {
blocked = !blocked blocked = !blocked
launch(Dispatchers.Unconfined) { AppDatabase.instance.clientRecordDao.update(this@apply) } GlobalScope.launch(Dispatchers.Unconfined) {
AppDatabase.instance.clientRecordDao.update(this@apply)
}
} }
IpNeighbourMonitor.instance?.flush() IpNeighbourMonitor.instance?.flush()
if (!wasWorking && item.itemId == R.id.block) { if (!wasWorking && item.itemId == R.id.block) {
@@ -150,7 +149,7 @@ class ClientsFragment : Fragment(), MainScope by MainScope.Supervisor() {
} }
R.id.stats -> { R.id.stats -> {
binding.client?.let { client -> binding.client?.let { client ->
launch(Dispatchers.Unconfined) { scope.launch {
StatsDialogFragment().withArg(StatsArg( StatsDialogFragment().withArg(StatsArg(
client.title.value ?: return@launch, client.title.value ?: return@launch,
AppDatabase.instance.trafficRecordDao.queryStats(client.mac) AppDatabase.instance.trafficRecordDao.queryStats(client.mac)
@@ -205,6 +204,7 @@ class ClientsFragment : Fragment(), MainScope by MainScope.Supervisor() {
} }
} }
private val scope = MainScope() + Dispatchers.Unconfined
private lateinit var binding: FragmentClientsBinding private lateinit var binding: FragmentClientsBinding
private val adapter = ClientAdapter() private val adapter = ClientAdapter()
private var rates = HashMap<Pair<String, Long>, TrafficRate>() private var rates = HashMap<Pair<String, Long>, TrafficRate>()
@@ -237,7 +237,7 @@ class ClientsFragment : Fragment(), MainScope by MainScope.Supervisor() {
} }
override fun onDestroy() { override fun onDestroy() {
job.cancel() scope.cancel()
super.onDestroy() super.onDestroy()
} }
} }

View File

@@ -163,7 +163,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
override val type get() = VIEW_TYPE_BLUETOOTH override val type get() = VIEW_TYPE_BLUETOOTH
override val isStarted get() = tethering.active == true override val isStarted get() = tethering.active == true
override fun onException() = ManageBar.start(parent.requireContext()) override fun onException() = ManageBar.start(parent.context ?: app)
override fun start() = BluetoothTethering.start(this) override fun start() = BluetoothTethering.start(this)
override fun stop() { override fun stop() {

View File

@@ -103,7 +103,7 @@ class TetheringFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClick
} }
private fun updateMonitorList(canMonitor: List<String> = emptyList()) { private fun updateMonitorList(canMonitor: List<String> = emptyList()) {
val item = requireActivity().toolbar.menu.findItem(R.id.monitor) ?: return // assuming no longer foreground val item = activity?.toolbar?.menu?.findItem(R.id.monitor) ?: return // assuming no longer foreground
item.isNotGone = canMonitor.isNotEmpty() item.isNotGone = canMonitor.isNotEmpty()
item.subMenu.apply { item.subMenu.apply {
clear() clear()

View File

@@ -1,14 +0,0 @@
package be.mygod.vpnhotspot.util
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
interface MainScope : CoroutineScope {
class Supervisor : MainScope {
override val job = SupervisorJob()
}
val job: Job
override val coroutineContext get() = Dispatchers.Main + job
}

View File

@@ -6,11 +6,15 @@
--> -->
<string name="repeater_configure_failure">Действительный конфиг не найден. Пожалуйста, сначала запустите ретранслятор.</string> <string name="repeater_configure_failure">Действительный конфиг не найден. Пожалуйста, сначала запустите ретранслятор.</string>
<string name="repeater_reset_credentials">Сброс</string>
<string name="repeater_reset_credentials_success">Сброс учетных данных.</string>
<string name="repeater_reset_credentials_failure">Не удалось сбросить учетные данные (причина:%s)</string>
<string name="repeater_clean_pog_failure">Не удалось удалить избыточную группу P2P (причина: %s)</string> <string name="repeater_clean_pog_failure">Не удалось удалить избыточную группу P2P (причина: %s)</string>
<string name="repeater_p2p_unavailable">Wi-Fi директ недоступен, пожалуйста включите Wi-Fi</string> <string name="repeater_p2p_unavailable">Wi-Fi директ недоступен, пожалуйста включите Wi-Fi</string>
<string name="repeater_create_group_failure">Не удалось создать группу P2P (причина: %s)</string> <string name="repeater_create_group_failure">Не удалось создать группу P2P (причина: %s)</string>
<string name="repeater_remove_group_failure">Не удалось удалить группу P2P (причина: %s)</string> <string name="repeater_remove_group_failure">Не удалось удалить группу P2P (причина: %s)</string>
<string name="repeater_remove_old_group_failure">Не удалось удалить старую группу P2P (причина:%s)</string>
<string name="repeater_failure_reason_error">внутренняя ошибка</string> <string name="repeater_failure_reason_error">внутренняя ошибка</string>
<string name="repeater_failure_reason_p2p_unsupported">Wi-Fi напрямую не поддерживается</string> <string name="repeater_failure_reason_p2p_unsupported">Wi-Fi напрямую не поддерживается</string>
@@ -31,12 +35,15 @@
<string name="clients_popup_block_service_inactive">Включите службу для этого интерфейса, чтобы заблокировать клиента.</string> <string name="clients_popup_block_service_inactive">Включите службу для этого интерфейса, чтобы заблокировать клиента.</string>
<string name="clients_popup_unblock">Разблокировать</string> <string name="clients_popup_unblock">Разблокировать</string>
<string name="clients_popup_stats">Статистика…</string> <string name="clients_popup_stats">Статистика…</string>
<string name="clients_mac_lookup_unexpected_error">Сервер вернул ошибку для %1$s: %2$s</string>
<string name="clients_nickname_title">Никнэйм для %s</string> <string name="clients_nickname_title">Никнэйм для %s</string>
<string name="clients_nickname_set_to_vendor">Имя вендора</string>
<string name="clients_stats_title">Статистика для %s</string> <string name="clients_stats_title">Статистика для %s</string>
<string name="notification_tethering_title">VPN-модем активен</string> <string name="notification_tethering_title">VPN-модем активен</string>
<string name="notification_channel_tethering">VPN модемная служба</string> <string name="notification_channel_tethering">VPN модемная служба</string>
<string name="notification_interfaces_inactive">Неактивных: %s</string>
<string name="failure_reason_unknown">Неизвестно #%d</string> <string name="failure_reason_unknown">Неизвестно #%d</string>
<string name="exception_interface_not_found">Ошибка: Нисходящий интерфейс не найден</string> <string name="exception_interface_not_found">Ошибка: Нисходящий интерфейс не найден</string>
@@ -55,7 +62,7 @@
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values-ru/donations__strings.xml --> <!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values-ru/donations__strings.xml -->
<string name="donations__button_close">Закрыть</string> <string name="donations__button_close">Закрыть</string>
<string name="donations__description">Считаете это приложение полезным?\\оддержите его разработку, отправив пожертвование разработчику!</string> <string name="donations__description">Считаете это приложение полезным?\nПоддержите его разработку, отправив пожертвование разработчику!</string>
<string name="donations__google_android_market">Google Play Store</string> <string name="donations__google_android_market">Google Play Store</string>
<string name="donations__google_android_market_not_supported_title">In-App пожертвования не поддерживаются.</string> <string name="donations__google_android_market_not_supported_title">In-App пожертвования не поддерживаются.</string>
<string name="donations__google_android_market_not_supported">Пожертвования через приложение не поддерживаются. Google Play Store установлен правильно?</string> <string name="donations__google_android_market_not_supported">Пожертвования через приложение не поддерживаются. Google Play Store установлен правильно?</string>