1
mobile/.gitignore
vendored
1
mobile/.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
/build
|
||||
/debug
|
||||
/release
|
||||
/google/
|
||||
|
||||
# tests aren't ready yet
|
||||
/src/androidTest
|
||||
|
||||
@@ -11,8 +11,8 @@ android {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
resConfigs "zh-rCN"
|
||||
versionCode 25
|
||||
versionName "1.3.4"
|
||||
versionCode 26
|
||||
versionName "1.3.5"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
@@ -26,11 +26,23 @@ android {
|
||||
}
|
||||
}
|
||||
dataBinding.enabled = true
|
||||
flavorDimensions("freedom")
|
||||
productFlavors {
|
||||
freedom {
|
||||
dimension "freedom"
|
||||
buildConfigField "boolean", "DONATIONS", "true"
|
||||
}
|
||||
google {
|
||||
dimension "freedom"
|
||||
buildConfigField "boolean", "DONATIONS", "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
kapt "androidx.databinding:databinding-compiler:$androidPluginVersion"
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.android.billingclient:billing:1.1'
|
||||
implementation "com.android.support:customtabs:$supportLibraryVersion"
|
||||
implementation "com.android.support:design:$supportLibraryVersion"
|
||||
implementation "com.android.support:preference-v14:$supportLibraryVersion"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.BILLING"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||
|
||||
103
mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt
Normal file
103
mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt
Normal file
@@ -0,0 +1,103 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewStub
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
import android.widget.Spinner
|
||||
import com.android.billingclient.api.*
|
||||
import com.crashlytics.android.Crashlytics
|
||||
|
||||
/**
|
||||
* Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/java/org/sufficientlysecure/donations/DonationsFragment.java
|
||||
*/
|
||||
class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientStateListener,
|
||||
SkuDetailsResponseListener, ConsumeResponseListener {
|
||||
companion object {
|
||||
private const val TAG = "EBegFragment"
|
||||
}
|
||||
|
||||
private lateinit var billingClient: BillingClient
|
||||
private lateinit var googleSpinner: Spinner
|
||||
private var skus: MutableList<SkuDetails>? = null
|
||||
set(value) {
|
||||
field = value
|
||||
googleSpinner.apply {
|
||||
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item,
|
||||
value?.map { it.price } ?: emptyList())
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
setAdapter(adapter)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
inflater.inflate(R.layout.fragment_ebeg, container, false)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
googleSpinner = view.findViewById(R.id.donations__google_android_market_spinner)
|
||||
billingClient = BillingClient.newBuilder(view.context).setListener(this).build()
|
||||
onBillingServiceDisconnected()
|
||||
view.findViewById<Button>(R.id.donations__google_android_market_donate_button).setOnClickListener {
|
||||
val skus = skus
|
||||
if (skus == null) {
|
||||
openDialog(android.R.drawable.ic_dialog_alert,
|
||||
R.string.donations__google_android_market_not_supported_title,
|
||||
getString(R.string.donations__google_android_market_not_supported))
|
||||
} else billingClient.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder()
|
||||
.setSku(skus[googleSpinner.selectedItemPosition].sku).setType(BillingClient.SkuType.INAPP).build())
|
||||
}
|
||||
@Suppress("ConstantConditionIf")
|
||||
if (BuildConfig.DONATIONS) (view.findViewById<ViewStub>(R.id.donations__more_stub).inflate() as Button)
|
||||
.setOnClickListener {
|
||||
(activity as MainActivity).launchUrl(Uri.parse("https://mygod.be/donate/"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun openDialog(icon: Int, title: Int, message: String) = AlertDialog.Builder(requireContext()).apply {
|
||||
setIcon(icon)
|
||||
setTitle(title)
|
||||
setMessage(message)
|
||||
isCancelable = true
|
||||
setNeutralButton(R.string.donations__button_close) { dialog, _ -> dialog.dismiss() }
|
||||
}.show()
|
||||
|
||||
override fun onBillingServiceDisconnected() {
|
||||
skus = null
|
||||
billingClient.startConnection(this)
|
||||
}
|
||||
override fun onBillingSetupFinished(responseCode: Int) {
|
||||
if (responseCode == BillingClient.BillingResponse.OK) {
|
||||
billingClient.querySkuDetailsAsync(
|
||||
SkuDetailsParams.newBuilder().apply {
|
||||
setSkusList(listOf("donate001", "donate002", "donate005", "donate010", "donate020", "donate050",
|
||||
"donate100", "donate200", "donatemax"))
|
||||
setType(BillingClient.SkuType.INAPP)
|
||||
}.build(), this)
|
||||
} else Crashlytics.log(Log.ERROR, TAG, "onBillingSetupFinished: $responseCode")
|
||||
}
|
||||
|
||||
override fun onSkuDetailsResponse(responseCode: Int, skuDetailsList: MutableList<SkuDetails>?) {
|
||||
if (responseCode == BillingClient.BillingResponse.OK) skus = skuDetailsList
|
||||
else Crashlytics.log(Log.ERROR, TAG, "onSkuDetailsResponse: $responseCode")
|
||||
}
|
||||
|
||||
override fun onPurchasesUpdated(responseCode: Int, purchases: MutableList<Purchase>?) {
|
||||
if (responseCode == BillingClient.BillingResponse.OK && purchases != null) {
|
||||
// directly consume in-app purchase, so that people can donate multiple times
|
||||
purchases.forEach { billingClient.consumeAsync(it.purchaseToken, this) }
|
||||
} else Crashlytics.log(Log.ERROR, TAG, "onPurchasesUpdated: $responseCode")
|
||||
}
|
||||
override fun onConsumeResponse(responseCode: Int, purchaseToken: String?) {
|
||||
if (responseCode == BillingClient.BillingResponse.OK) {
|
||||
openDialog(android.R.drawable.ic_dialog_info, R.string.donations__thanks_dialog_title,
|
||||
getString(R.string.donations__thanks_dialog))
|
||||
} else Crashlytics.log(Log.ERROR, TAG, "onConsumeResponse: $responseCode")
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.databinding.DataBindingUtil
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.support.customtabs.CustomTabsIntent
|
||||
import android.support.design.internal.BottomNavigationMenuView
|
||||
import android.support.design.widget.BottomNavigationView
|
||||
import android.support.v4.app.Fragment
|
||||
@@ -23,6 +26,12 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var badge: QBadgeView
|
||||
private var clients: ClientMonitorService.Binder? = null
|
||||
private val customTabsIntent by lazy {
|
||||
CustomTabsIntent.Builder()
|
||||
.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary))
|
||||
.build()
|
||||
}
|
||||
fun launchUrl(url: Uri) = customTabsIntent.launchUrl(this, url)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -76,4 +85,9 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
||||
|
||||
private fun displayFragment(fragment: Fragment) =
|
||||
supportFragmentManager.beginTransaction().replace(R.id.fragmentHolder, fragment).commitAllowingStateLoss()
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
supportFragmentManager.findFragmentByTag("donationsFragment")?.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.customtabs.CustomTabsIntent
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v4.content.FileProvider
|
||||
import android.support.v7.preference.Preference
|
||||
import android.widget.Toast
|
||||
@@ -26,12 +24,6 @@ import java.net.NetworkInterface
|
||||
import java.net.SocketException
|
||||
|
||||
class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
private val customTabsIntent by lazy {
|
||||
CustomTabsIntent.Builder()
|
||||
.setToolbarColor(ContextCompat.getColor(requireContext(), R.color.colorPrimary))
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
preferenceManager.preferenceDataStore = SharedPreferenceDataStore(app.pref)
|
||||
addPreferencesFromResource(R.xml.pref_settings)
|
||||
@@ -98,7 +90,11 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
true
|
||||
}
|
||||
findPreference("misc.source").setOnPreferenceClickListener {
|
||||
customTabsIntent.launchUrl(requireActivity(), Uri.parse("https://github.com/Mygod/VPNHotspot"))
|
||||
(activity as MainActivity).launchUrl(Uri.parse("https://github.com/Mygod/VPNHotspot"))
|
||||
true
|
||||
}
|
||||
findPreference("misc.donate").setOnPreferenceClickListener {
|
||||
EBegFragment().show(fragmentManager, "ebeg_fragment")
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
10
mobile/src/main/res/drawable/ic_action_card_giftcard.xml
Normal file
10
mobile/src/main/res/drawable/ic_action_card_giftcard.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,6h-2.18c0.11,-0.31 0.18,-0.65 0.18,-1 0,-1.66 -1.34,-3 -3,-3 -1.05,0 -1.96,0.54 -2.5,1.35l-0.5,0.67 -0.5,-0.68C10.96,2.54 10.05,2 9,2 7.34,2 6,3.34 6,5c0,0.35 0.07,0.69 0.18,1L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM15,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM9,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM20,19L4,19v-2h16v2zM20,14L4,14L4,8h5.08L7,10.83 8.62,12 11,8.76l1,-1.36 1,1.36L15.38,12 17,10.83 14.92,8L20,8v6z"/>
|
||||
</vector>
|
||||
69
mobile/src/main/res/layout/fragment_ebeg.xml
Normal file
69
mobile/src/main/res/layout/fragment_ebeg.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Based on:
|
||||
~ https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/layout/donations__fragment.xml
|
||||
~ https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/layout/donations__fragment_google.xml
|
||||
~ -->
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:isScrollContainer="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/donations__description"
|
||||
android:textAppearance="@android:style/TextAppearance.Small" />
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dp"
|
||||
android:text="@string/donations__google_android_market"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="5dp"
|
||||
android:paddingTop="5dp"
|
||||
android:text="@string/donations__google_android_market_description"
|
||||
android:textAppearance="@android:style/TextAppearance.Small" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="5dp" >
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/donations__google_android_market_spinner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:prompt="@string/donations__google_android_market_text" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/donations__google_android_market_donate_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/donations__google_android_market_donate_button" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
<ViewStub
|
||||
android:id="@+id/donations__more_stub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout="@layout/fragment_ebeg_more" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
6
mobile/src/main/res/layout/fragment_ebeg_more.xml
Normal file
6
mobile/src/main/res/layout/fragment_ebeg_more.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Button xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/donations__more_donate_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_misc_donate_more"/>
|
||||
@@ -74,6 +74,9 @@
|
||||
<string name="settings_misc_logcat_summary">这种非常有用哇</string>
|
||||
<string name="settings_misc_source">查看 GitHub 上的源码</string>
|
||||
<string name="settings_misc_source_summary">Star, 提交 issues, 合作</string>
|
||||
<string name="settings_misc_donate">捐款</string>
|
||||
<string name="settings_misc_donate_summary">请给我钱</string>
|
||||
<string name="settings_misc_donate_more">PayPal, Flattr 等其他方式…</string>
|
||||
|
||||
<string name="notification_tethering_title">VPN 共享已启用</string>
|
||||
<string name="notification_channel_tethering">VPN 共享服务</string>
|
||||
@@ -94,4 +97,17 @@
|
||||
<string name="credentials_password_too_short" msgid="7502749986405522663">"密码至少应包含 8 个字符。"</string>
|
||||
<string name="wifi_save" msgid="3331121567988522826">"保存"</string>
|
||||
<string name="wifi_cancel" msgid="6763568902542968964">"取消"</string>
|
||||
|
||||
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values-zh/donations__strings.xml -->
|
||||
<string name="donations__button_close">关闭</string>
|
||||
<string name="donations__google_android_market">Google Play 商店</string>
|
||||
<string name="donations__google_android_market_not_supported_title">不支持 In-App 捐赠。</string>
|
||||
<string name="donations__google_android_market_not_supported">不支持 In-App 捐赠。你的 Google Play 商店是否安装正确了呢?</string>
|
||||
<string name="donations__google_android_market_donate_button">捐赠!</string>
|
||||
<string name="donations__google_android_market_text">捐赠多少?</string>
|
||||
<string name="donations__thanks_dialog_title">谢谢!</string>
|
||||
<string name="donations__thanks_dialog">谢谢捐赠!\n非常感谢您!</string>
|
||||
|
||||
<string name="donations__description">觉得此应用很有用?\n捐赠给该开发者以支持此应用的开发!</string>
|
||||
<string name="donations__google_android_market_description">Google 收取 30% 的费用</string>
|
||||
</resources>
|
||||
|
||||
@@ -79,6 +79,9 @@
|
||||
<string name="settings_misc_logcat_summary">Such useful very wow</string>
|
||||
<string name="settings_misc_source">View on GitHub</string>
|
||||
<string name="settings_misc_source_summary">Star, submit issues and contribute</string>
|
||||
<string name="settings_misc_donate">Donate</string>
|
||||
<string name="settings_misc_donate_summary">I love money</string>
|
||||
<string name="settings_misc_donate_more">PayPal, Flattr, more…</string>
|
||||
|
||||
<string name="notification_tethering_title">VPN tethering active</string>
|
||||
<string name="notification_channel_tethering">VPN Tethering Service</string>
|
||||
@@ -101,4 +104,16 @@
|
||||
<string name="credentials_password_too_short">The password must have at least 8 characters.</string>
|
||||
<string name="wifi_save">Save</string>
|
||||
<string name="wifi_cancel">Cancel</string>
|
||||
|
||||
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values/donations__strings.xml -->
|
||||
<string name="donations__button_close">Close</string>
|
||||
<string name="donations__description">Do you find this application useful?\nSupport its development by sending a donation to the developer!</string>
|
||||
<string name="donations__google_android_market">Google Play Store</string>
|
||||
<string name="donations__google_android_market_not_supported_title">In-App Donations are not supported.</string>
|
||||
<string name="donations__google_android_market_not_supported">In-App Donations are not supported. Is Google Play Store installed correctly?</string>
|
||||
<string name="donations__google_android_market_description">Google charges a fee of 30%</string>
|
||||
<string name="donations__google_android_market_donate_button">Donate!</string>
|
||||
<string name="donations__google_android_market_text">How much?</string>
|
||||
<string name="donations__thanks_dialog_title">Thanks!</string>
|
||||
<string name="donations__thanks_dialog">Thanks for donating!\nI really appreciate this!</string>
|
||||
</resources>
|
||||
|
||||
@@ -48,5 +48,10 @@
|
||||
android:icon="@drawable/ic_toggle_star"
|
||||
android:title="@string/settings_misc_source"
|
||||
android:summary="@string/settings_misc_source_summary"/>
|
||||
<Preference
|
||||
android:key="misc.donate"
|
||||
android:icon="@drawable/ic_action_card_giftcard"
|
||||
android:title="@string/settings_misc_donate"
|
||||
android:summary="@string/settings_misc_donate_summary"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
||||
Reference in New Issue
Block a user