Add the best feature ever (E-begging)

This reverts commit ebb6061a6e.
This commit is contained in:
Mygod
2018-07-13 15:05:33 +08:00
parent 2e912bf767
commit 33cd906f65
12 changed files with 259 additions and 11 deletions

1
mobile/.gitignore vendored
View File

@@ -1,6 +1,7 @@
/build /build
/debug /debug
/release /release
/google/
# tests aren't ready yet # tests aren't ready yet
/src/androidTest /src/androidTest

View File

@@ -11,8 +11,8 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 28
resConfigs "zh-rCN" resConfigs "zh-rCN"
versionCode 25 versionCode 26
versionName "1.3.4" versionName "1.3.5"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
@@ -26,11 +26,23 @@ android {
} }
} }
dataBinding.enabled = true dataBinding.enabled = true
flavorDimensions("freedom")
productFlavors {
freedom {
dimension "freedom"
buildConfigField "boolean", "DONATIONS", "true"
}
google {
dimension "freedom"
buildConfigField "boolean", "DONATIONS", "false"
}
}
} }
dependencies { dependencies {
kapt "androidx.databinding:databinding-compiler:$androidPluginVersion" kapt "androidx.databinding:databinding-compiler:$androidPluginVersion"
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.billingclient:billing:1.1'
implementation "com.android.support:customtabs:$supportLibraryVersion" implementation "com.android.support:customtabs:$supportLibraryVersion"
implementation "com.android.support:design:$supportLibraryVersion" implementation "com.android.support:design:$supportLibraryVersion"
implementation "com.android.support:preference-v14:$supportLibraryVersion" implementation "com.android.support:preference-v14:$supportLibraryVersion"

View File

@@ -21,6 +21,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_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.BLUETOOTH"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>

View 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")
}
}

View File

@@ -1,10 +1,13 @@
package be.mygod.vpnhotspot package be.mygod.vpnhotspot
import android.content.ComponentName import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.databinding.DataBindingUtil import android.databinding.DataBindingUtil
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.support.customtabs.CustomTabsIntent
import android.support.design.internal.BottomNavigationMenuView import android.support.design.internal.BottomNavigationMenuView
import android.support.design.widget.BottomNavigationView import android.support.design.widget.BottomNavigationView
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
@@ -23,6 +26,12 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
private lateinit var badge: QBadgeView private lateinit var badge: QBadgeView
private var clients: ClientMonitorService.Binder? = null 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?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -76,4 +85,9 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
private fun displayFragment(fragment: Fragment) = private fun displayFragment(fragment: Fragment) =
supportFragmentManager.beginTransaction().replace(R.id.fragmentHolder, fragment).commitAllowingStateLoss() 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)
}
} }

View File

@@ -5,8 +5,6 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.support.customtabs.CustomTabsIntent
import android.support.v4.content.ContextCompat
import android.support.v4.content.FileProvider import android.support.v4.content.FileProvider
import android.support.v7.preference.Preference import android.support.v7.preference.Preference
import android.widget.Toast import android.widget.Toast
@@ -26,12 +24,6 @@ import java.net.NetworkInterface
import java.net.SocketException import java.net.SocketException
class SettingsPreferenceFragment : PreferenceFragmentCompat() { 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?) { override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = SharedPreferenceDataStore(app.pref) preferenceManager.preferenceDataStore = SharedPreferenceDataStore(app.pref)
addPreferencesFromResource(R.xml.pref_settings) addPreferencesFromResource(R.xml.pref_settings)
@@ -98,7 +90,11 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
true true
} }
findPreference("misc.source").setOnPreferenceClickListener { 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 true
} }
} }

View 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>

View 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>

View 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"/>

View File

@@ -74,6 +74,9 @@
<string name="settings_misc_logcat_summary">这种非常有用哇</string> <string name="settings_misc_logcat_summary">这种非常有用哇</string>
<string name="settings_misc_source">查看 GitHub 上的源码</string> <string name="settings_misc_source">查看 GitHub 上的源码</string>
<string name="settings_misc_source_summary">Star, 提交 issues, 合作</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_tethering_title">VPN 共享已启用</string>
<string name="notification_channel_tethering">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="credentials_password_too_short" msgid="7502749986405522663">"密码至少应包含 8 个字符。"</string>
<string name="wifi_save" msgid="3331121567988522826">"保存"</string> <string name="wifi_save" msgid="3331121567988522826">"保存"</string>
<string name="wifi_cancel" msgid="6763568902542968964">"取消"</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> </resources>

View File

@@ -79,6 +79,9 @@
<string name="settings_misc_logcat_summary">Such useful very wow</string> <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">View on GitHub</string>
<string name="settings_misc_source_summary">Star, submit issues and contribute</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_tethering_title">VPN tethering active</string>
<string name="notification_channel_tethering">VPN Tethering Service</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="credentials_password_too_short">The password must have at least 8 characters.</string>
<string name="wifi_save">Save</string> <string name="wifi_save">Save</string>
<string name="wifi_cancel">Cancel</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> </resources>

View File

@@ -48,5 +48,10 @@
android:icon="@drawable/ic_toggle_star" android:icon="@drawable/ic_toggle_star"
android:title="@string/settings_misc_source" android:title="@string/settings_misc_source"
android:summary="@string/settings_misc_source_summary"/> 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> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>