Skip to content

Commit 942a215

Browse files
committed
Add terms and privacy policy dialog
1 parent 5fb4f3a commit 942a215

File tree

29 files changed

+149
-18
lines changed

29 files changed

+149
-18
lines changed

app/build.gradle.kts

+5-5
Original file line numberDiff line numberDiff line change
@@ -153,26 +153,26 @@ dependencies {
153153
val kgraphql = "0.19.0"
154154
val ktor = "3.0.0-beta-1"
155155
val media3 = "1.2.1"
156-
val compose = "1.6.0"
156+
val compose = "1.6.1"
157157

158-
implementation(platform("androidx.compose:compose-bom:2023.10.01"))
158+
implementation(platform("androidx.compose:compose-bom:2024.01.00"))
159159

160160
// https://github.com/google/accompanist/releases
161161
implementation("androidx.activity:activity-compose:1.8.2")
162162
implementation("androidx.compose.runtime:runtime:$compose")
163163
implementation("androidx.compose.ui:ui:$compose")
164164
implementation("androidx.compose.foundation:foundation:$compose")
165165
implementation("androidx.compose.foundation:foundation-layout:$compose")
166-
implementation("androidx.compose.material3:material3:1.2.0-rc01")
166+
implementation("androidx.compose.material3:material3:1.2.0")
167167
implementation("androidx.compose.material:material-icons-extended:$compose")
168168
implementation("com.google.accompanist:accompanist-drawablepainter:0.34.0")
169169
// implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha12")
170170

171171
// https://developer.android.com/jetpack/androidx/releases/navigation
172-
implementation("androidx.navigation:navigation-compose:2.7.6")
172+
implementation("androidx.navigation:navigation-compose:2.7.7")
173173

174174
releaseImplementation(platform("com.google.firebase:firebase-bom:32.2.3"))
175-
releaseImplementation("com.google.firebase:firebase-crashlytics-ktx:18.6.1")
175+
releaseImplementation("com.google.firebase:firebase-crashlytics-ktx:18.6.2")
176176

177177
// Media3
178178
implementation("androidx.media3:media3-exoplayer:$media3")

app/src/main/java/com/ismartcoding/plain/data/preference/Preferences.kt

+5
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ object WebPreference : BasePreference<Boolean>() {
221221
}
222222
}
223223

224+
object AgreeTermsPreference : BasePreference<Boolean>() {
225+
override val default = false
226+
override val key = booleanPreferencesKey("agree_terms")
227+
}
228+
224229
object ExchangeRatePreference : BasePreference<String>() {
225230
override val default = ""
226231
override val key = stringPreferencesKey("exchange")

app/src/main/java/com/ismartcoding/plain/helpers/UrlHelper.kt

+8
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,12 @@ object UrlHelper {
5151

5252
return "https://policy.plain.icu/policy.html"
5353
}
54+
55+
fun getTermsUrl(): String {
56+
if (BuildConfig.CHANNEL == AppChannelType.CHINA.name) {
57+
return "https://policy.plain.icu/policy-cn.html"
58+
}
59+
60+
return "https://policy.plain.icu/terms.html"
61+
}
5462
}

app/src/main/java/com/ismartcoding/plain/ui/MainActivity.kt

+61-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ package com.ismartcoding.plain.ui
22

33
import android.annotation.SuppressLint
44
import android.app.Activity
5+
import android.content.Context
56
import android.content.Intent
67
import android.content.res.Configuration
78
import android.database.CursorWindow
89
import android.net.Uri
910
import android.os.Bundle
1011
import android.provider.Settings
12+
import android.text.SpannableString
13+
import android.text.Spanned
14+
import android.text.method.LinkMovementMethod
15+
import android.text.style.ClickableSpan
16+
import android.view.View
1117
import android.view.WindowManager
18+
import android.widget.TextView
1219
import android.widget.Toast
1320
import androidx.activity.compose.setContent
1421
import androidx.activity.enableEdgeToEdge
@@ -26,14 +33,18 @@ import com.ismartcoding.lib.channel.receiveEvent
2633
import com.ismartcoding.lib.channel.sendEvent
2734
import com.ismartcoding.lib.extensions.*
2835
import com.ismartcoding.lib.helpers.CoroutinesHelper.coIO
36+
import com.ismartcoding.lib.helpers.CoroutinesHelper.coMain
2937
import com.ismartcoding.lib.helpers.CoroutinesHelper.withIO
3038
import com.ismartcoding.lib.logcat.LogCat
39+
import com.ismartcoding.plain.BuildConfig
3140
import com.ismartcoding.plain.R
3241
import com.ismartcoding.plain.data.*
42+
import com.ismartcoding.plain.data.enums.AppChannelType
3343
import com.ismartcoding.plain.data.enums.ExportFileType
3444
import com.ismartcoding.plain.data.enums.Language
3545
import com.ismartcoding.plain.data.enums.PickFileTag
3646
import com.ismartcoding.plain.data.enums.PickFileType
47+
import com.ismartcoding.plain.data.preference.AgreeTermsPreference
3748
import com.ismartcoding.plain.data.preference.KeepScreenOnPreference
3849
import com.ismartcoding.plain.data.preference.SettingsProvider
3950
import com.ismartcoding.plain.data.preference.SystemScreenTimeoutPreference
@@ -45,12 +56,14 @@ import com.ismartcoding.plain.features.locale.LocaleHelper
4556
import com.ismartcoding.plain.features.locale.LocaleHelper.getStringF
4657
import com.ismartcoding.plain.helpers.AppHelper
4758
import com.ismartcoding.plain.helpers.ScreenHelper
59+
import com.ismartcoding.plain.helpers.UrlHelper
4860
import com.ismartcoding.plain.mediaProjectionManager
4961
import com.ismartcoding.plain.services.NotificationListenerMonitorService
5062
import com.ismartcoding.plain.services.ScreenMirrorService
5163
import com.ismartcoding.plain.ui.extensions.*
5264
import com.ismartcoding.plain.ui.helpers.DialogHelper
5365
import com.ismartcoding.plain.ui.helpers.FilePickHelper
66+
import com.ismartcoding.plain.ui.helpers.WebHelper
5467
import com.ismartcoding.plain.ui.models.MainViewModel
5568
import com.ismartcoding.plain.ui.models.ShowMessageEvent
5669
import com.ismartcoding.plain.ui.page.Main
@@ -63,6 +76,7 @@ import kotlinx.coroutines.Dispatchers
6376
import kotlinx.coroutines.delay
6477
import kotlinx.coroutines.launch
6578
import java.lang.ref.WeakReference
79+
import kotlin.system.exitProcess
6680

6781
class MainActivity : AppCompatActivity() {
6882
private var pickFileType = PickFileType.IMAGE
@@ -159,11 +173,18 @@ class MainActivity : AppCompatActivity() {
159173
}
160174
}
161175

162-
checkNotificationPermission()
163-
164176
AudioPlayer.ensurePlayer(this@MainActivity)
165177
coIO {
166178
try {
179+
if (BuildConfig.CHANNEL == AppChannelType.CHINA.name && !AgreeTermsPreference.getAsync(this@MainActivity)) {
180+
coMain {
181+
showTermsAndPrivacyDialog(this@MainActivity)
182+
}
183+
} else {
184+
coMain {
185+
checkNotificationPermission()
186+
}
187+
}
167188
startService(Intent(this@MainActivity, NotificationListenerMonitorService::class.java))
168189
} catch (ex: Exception) {
169190
LogCat.e(ex.toString())
@@ -323,6 +344,44 @@ class MainActivity : AppCompatActivity() {
323344
pickFileActivityLauncher.launch(FilePickHelper.getPickFileIntent(event.multiple))
324345
}
325346

347+
private fun showTermsAndPrivacyDialog(context: Context) {
348+
val message = "请您认真阅读《用户协议》和《隐私政策》的全部条款,接受后可开始使用我们的服务。"
349+
350+
val startIndexUserAgreement = message.indexOf("《用户协议》")
351+
val startIndexPrivacyPolicy = message.indexOf("《隐私政策》")
352+
353+
val spannableString = SpannableString(message)
354+
spannableString.setSpan(object : ClickableSpan() {
355+
override fun onClick(widget: View) {
356+
WebHelper.open(context, UrlHelper.getTermsUrl())
357+
}
358+
}, startIndexUserAgreement, startIndexUserAgreement + 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
359+
spannableString.setSpan(object : ClickableSpan() {
360+
override fun onClick(widget: View) {
361+
WebHelper.open(context, UrlHelper.getPolicyUrl())
362+
}
363+
}, startIndexPrivacyPolicy, startIndexPrivacyPolicy + 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
364+
val dialog = MaterialAlertDialogBuilder(context)
365+
.setTitle("温馨提示")
366+
.setCancelable(false)
367+
.setPositiveButton("同意并继续") { _, _ ->
368+
checkNotificationPermission()
369+
coIO {
370+
AgreeTermsPreference.putAsync(context, true)
371+
}
372+
}
373+
.setNegativeButton("不同意") { _, _ ->
374+
this@MainActivity.finish()
375+
}
376+
.create()
377+
378+
dialog.setView(TextView(context).apply {
379+
text = spannableString
380+
movementMethod = LinkMovementMethod.getInstance()
381+
}, context.dp2px(24), context.dp2px(28), context.dp2px(24), context.dp2px(28))
382+
dialog.show()
383+
}
384+
326385
companion object {
327386
lateinit var instance: WeakReference<MainActivity>
328387
}

app/src/main/java/com/ismartcoding/plain/ui/base/LoadingDialog.kt

+4-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.ismartcoding.plain.ui.base
33
import androidx.compose.foundation.layout.Column
44
import androidx.compose.foundation.layout.padding
55
import androidx.compose.material3.AlertDialog
6+
import androidx.compose.material3.BasicAlertDialog
67
import androidx.compose.material3.CircularProgressIndicator
78
import androidx.compose.material3.ExperimentalMaterial3Api
89
import androidx.compose.runtime.Composable
@@ -17,8 +18,8 @@ fun LoadingDialog(
1718
onDismiss: () -> Unit,
1819
) {
1920
if (showDialog) {
20-
AlertDialog(
21-
onDismissRequest = { onDismiss() },
21+
BasicAlertDialog(onDismissRequest = { onDismiss() },
22+
properties = DialogProperties(dismissOnClickOutside = false),
2223
content = {
2324
Column(
2425
Modifier.padding(vertical = 16.dp),
@@ -27,8 +28,6 @@ fun LoadingDialog(
2728
modifier = Modifier.padding(bottom = 8.dp),
2829
)
2930
}
30-
},
31-
properties = DialogProperties(dismissOnClickOutside = false),
32-
)
31+
})
3332
}
3433
}

app/src/main/java/com/ismartcoding/plain/ui/base/pullrefresh/LoadMoreRefreshContent.kt

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ fun RefreshLayoutState.LoadMoreRefreshContent(bottomNoMoreData: Boolean = false)
3535
animation = tween(durationMillis = 1000, easing = LinearEasing),
3636
repeatMode = RepeatMode.Restart,
3737
),
38+
label = "",
3839
).value
3940
}
4041
Row(

app/src/main/java/com/ismartcoding/plain/ui/base/subsampling/ComposeSubsamplingScaleImageState.kt

-1
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,6 @@ class ComposeSubsamplingScaleImageState internal constructor(
968968
return when (gestureAnimationEasing) {
969969
GestureAnimationEasing.EaseInOutQuad -> easeInOutQuad(time, from, change, duration)
970970
GestureAnimationEasing.EaseOutQuad -> easeOutQuad(time, from, change, duration)
971-
else -> throw java.lang.IllegalStateException("Unexpected easing type: $gestureAnimationEasing")
972971
}
973972
}
974973

app/src/main/java/com/ismartcoding/plain/ui/components/chat/ChatInput.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.padding
1212
import androidx.compose.foundation.shape.RoundedCornerShape
1313
import androidx.compose.foundation.text.KeyboardOptions
1414
import androidx.compose.material.icons.Icons
15+
import androidx.compose.material.icons.automirrored.outlined.Send
1516
import androidx.compose.material.icons.outlined.Folder
1617
import androidx.compose.material.icons.outlined.Image
1718
import androidx.compose.material.icons.outlined.Send
@@ -93,7 +94,7 @@ fun ChatInput(
9394
}
9495
Spacer(modifier = Modifier.weight(1f))
9596
PIconButton(
96-
imageVector = Icons.Outlined.Send,
97+
imageVector = Icons.AutoMirrored.Outlined.Send,
9798
contentDescription = stringResource(R.string.send_message),
9899
tint = MaterialTheme.colorScheme.primary,
99100
) {

app/src/main/java/com/ismartcoding/plain/ui/components/home/HomeItemSocial.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Column
44
import androidx.compose.foundation.layout.ExperimentalLayoutApi
55
import androidx.compose.foundation.layout.width
66
import androidx.compose.material.icons.Icons
7+
import androidx.compose.material.icons.automirrored.outlined.Message
78
import androidx.compose.material.icons.outlined.Call
89
import androidx.compose.material.icons.outlined.Contacts
910
import androidx.compose.material.icons.outlined.Message
@@ -31,7 +32,7 @@ fun HomeItemSocial(
3132
)
3233
HomeItemFlow {
3334
GridItem(
34-
icon = Icons.Outlined.Message,
35+
icon = Icons.AutoMirrored.Outlined.Message,
3536
stringResource(id = R.string.messages),
3637
modifier = Modifier.width(itemWidth),
3738
) {

app/src/main/java/com/ismartcoding/plain/ui/components/home/HomeItemWork.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Column
44
import androidx.compose.foundation.layout.ExperimentalLayoutApi
55
import androidx.compose.foundation.layout.width
66
import androidx.compose.material.icons.Icons
7+
import androidx.compose.material.icons.automirrored.outlined.Notes
78
import androidx.compose.material.icons.outlined.Notes
89
import androidx.compose.material.icons.outlined.RssFeed
910
import androidx.compose.runtime.Composable
@@ -25,7 +26,7 @@ fun HomeItemWork(itemWidth: Dp) {
2526
)
2627
HomeItemFlow {
2728
GridItem(
28-
icon = Icons.Outlined.Notes,
29+
icon = Icons.AutoMirrored.Outlined.Notes,
2930
stringResource(id = R.string.notes),
3031
modifier = Modifier.width(itemWidth),
3132
) {

app/src/main/java/com/ismartcoding/plain/ui/page/Main.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ fun Main(viewModel: MainViewModel) {
182182
slideHorizontallyComposable(
183183
"${RouteName.CHAT_EDIT_TEXT.name}/{id}",
184184
arguments = listOf(navArgument("id") { type = NavType.StringType }),
185-
) { backStackEntry ->
185+
) {
186186
ChatEditTextPage(navController, sharedViewModel)
187187
}
188188
}

app/src/main/java/com/ismartcoding/plain/ui/page/settings/AboutPage.kt

+7
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ fun AboutPage(
7171
WebHelper.open(context, "https://ko-fi.com/ismartcoding")
7272
},
7373
)
74+
PListItem(
75+
title = stringResource(R.string.terms_of_use),
76+
showMore = true,
77+
onClick = {
78+
WebHelper.open(context, UrlHelper.getTermsUrl())
79+
},
80+
)
7481
PListItem(
7582
title = stringResource(R.string.privacy_policy),
7683
showMore = true,

app/src/main/java/com/ismartcoding/plain/ui/views/mergeimages/CombineNineRect.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object CombineNineRect {
99
count: Int,
1010
): List<CombineBitmapEntity> {
1111
val mCRC = generateColumnRowCountByCount(count)
12-
var mBitmapEntity: CombineBitmapEntity? = null
12+
var mBitmapEntity: CombineBitmapEntity?
1313
val perBitmapWidth =
1414
(
1515
(combineWidth - 1 * 2 * mCRC.columns) /

app/src/main/res/values-bn/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<string name="generate_password">পাসওয়ার্ড তৈরি করুন</string>
66
<string name="allow_remote_access_from_pc">পিসি থেকে দূরবর্তী অ্যাক্সেস অনুমোদন দিন</string>
77
<string name="privacy_policy">গোপনীয়তা নীতি</string>
8+
<string name="terms_of_use">ব্যবহারের শর্তাবলী</string>
89
<string name="grant_permission">অনুমতি দান করুন</string>
910
<string name="system_alert_window_warning">‘অন্য অ্যাপস উপর প্রদর্শন’ অনুমতি দেওয়া গুরুত্বপূর্ণ। এই অনুমতি না থাকলে, যদি অ্যাপটি ব্যাকগ্রাউন্ডে চলছে, আপনি অ্যাপ দ্বারা সৃষ্টিকৃত মৌলিক সিস্টেম ডায়ালগ, যেমন অনইনস্টলেশন নিশ্চিতকরণ ডায়ালগ, অনুমতি দেওয়া না থাকলে আপনি এটি হারতে পারেন।</string>
1011
<string name="advanced_https">এইচটিপিএস (উন্নত)</string>

app/src/main/res/values-de/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<string name="generate_password">Passwort generieren</string>
66
<string name="allow_remote_access_from_pc">Remote-Zugriff vom PC erlauben</string>
77
<string name="privacy_policy">Datenschutzrichtlinie</string>
8+
<string name="terms_of_use">Nutzungsbedingungen</string>
89
<string name="grant_permission">Berechtigung erteilen</string>
910
<string name="system_alert_window_warning">Die Gewährung der \'Über anderen Apps anzeigen\'-Berechtigung ist unerlässlich. Ohne diese Berechtigung könnten bei laufender App im Hintergrund wichtige Systemdialoge, wie etwa Deinstallationsbestätigungsdialoge, übersehen werden.</string>
1011
<string name="advanced_https">HTTPS (Fortgeschritten)</string>

app/src/main/res/values-es/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<string name="generate_password">Generar contraseña</string>
66
<string name="allow_remote_access_from_pc">Permitir acceso remoto desde PC</string>
77
<string name="privacy_policy">Política de privacidad</string>
8+
<string name="terms_of_use">Términos de uso</string>
89
<string name="grant_permission">Conceder permiso</string>
910
<string name="system_alert_window_warning">Conceder el permiso de \'Mostrar sobre otras aplicaciones\' es esencial. Sin este permiso, si la aplicación se está ejecutando en segundo plano, podrías perder diálogos cruciales del sistema provocados por la aplicación, como los diálogos de confirmación de desinstalación.</string>
1011
<string name="advanced_https">HTTPS (Avanzado)</string>

app/src/main/res/values-fr/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<string name="generate_password">Générer un mot de passe</string>
66
<string name="allow_remote_access_from_pc">Autoriser l\'accès à distance depuis un PC</string>
77
<string name="privacy_policy">Politique de confidentialité</string>
8+
<string name="terms_of_use">Conditions d\'utilisation</string>
89
<string name="grant_permission">Accorder l\'autorisation</string>
910
<string name="system_alert_window_warning">Accorder l\'autorisation \'Affichage par-dessus d\'autres applications\' est essentiel. Sans cette autorisation, si l\'application est en cours d\'exécution en arrière-plan, vous pourriez manquer des dialogues système cruciaux déclenchés par l\'application, tels que les dialogues de confirmation de désinstallation.</string>
1011
<string name="advanced_https">HTTPS (Avancé)</string>

app/src/main/res/values-hi/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<string name="generate_password">पासवर्ड बनाएं</string>
66
<string name="allow_remote_access_from_pc">पीसी से दूरस्थ पहुंच की अनुमति दें</string>
77
<string name="privacy_policy">गोपनीयता नीति</string>
8+
<string name="terms_of_use">उपयोग की शर्तें</string>
89
<string name="grant_permission">अनुमति प्रदान करें</string>
910
<string name="system_alert_window_warning">‘अन्य एप्लिकेशन्स पर प्रदर्शन’ अनुमति देना अत्यंत आवश्यक है। इस अनुमति के बिना, यदि ऐप बैकग्राउंड में चल रहा है, तो आप एप्लिकेशन द्वारा उत्पन्न होने वाले महत्वपूर्ण सिस्टम डायलॉग, जैसे कि अनइंस्टॉल की पुष्टि करने वाले डायलॉग, को छू सकते हैं।</string>
1011
<string name="advanced_https">एचटीटपीएस (उन्नत)</string>

app/src/main/res/values-it/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<string name="generate_password">Genera password</string>
66
<string name="allow_remote_access_from_pc">Consenti l\'accesso remoto dal PC</string>
77
<string name="privacy_policy">Informativa sulla privacy</string>
8+
<string name="terms_of_use">Termini di utilizzo</string>
89
<string name="grant_permission">Concedi il permesso</string>
910
<string name="system_alert_window_warning">Concedere il permesso \'Mostra sopra le altre app\' è essenziale. Senza questo permesso, se l\'app è in esecuzione in background, potresti perdere dialoghi di sistema cruciali generati dall\'app, come i dialoghi di conferma della disinstallazione.</string>
1011
<string name="advanced_https">HTTPS (Avanzato)</string>

app/src/main/res/values-ja/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<string name="generate_password">パスワードを生成</string>
66
<string name="allow_remote_access_from_pc">PCからのリモートアクセスを許可する</string>
77
<string name="privacy_policy">プライバシーポリシー</string>
8+
<string name="terms_of_use">利用規約</string>
89
<string name="grant_permission">許可を付与</string>
910
<string name="system_alert_window_warning">「他のアプリの上に表示」の許可を付与することが不可欠です。この許可がないと、アプリがバックグラウンドで実行されている場合に、アンインストール確認ダイアログなど、アプリによってトリガーされた重要なシステムダイアログが見逃される可能性があります。</string>
1011
<string name="advanced_https">HTTPS(高度)</string>

0 commit comments

Comments
 (0)