diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index c386e21..9e05d19 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -13,8 +13,8 @@ android {
applicationId = "com.haodustudio.DailyNotes"
minSdk = 24
targetSdk = 33
- versionCode = 5
- versionName = "1.0.4"
+ versionCode = 6
+ versionName = "1.0.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -68,6 +68,7 @@ dependencies {
implementation("com.squareup.retrofit2:converter-gson:2.6.2")
implementation("de.hdodenhof:circleimageview:3.1.0")
implementation("com.google.android.material:material:1.11.0")
+ implementation("io.sentry:sentry-android:7.13.0")
}
sentry {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f2c7c11..98cc103 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -41,6 +41,9 @@
+
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/BaseApplication.kt b/app/src/main/java/com/haodustudio/DailyNotes/BaseApplication.kt
index 6e6119f..42d57f2 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/BaseApplication.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/BaseApplication.kt
@@ -13,8 +13,11 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
+import com.haodustudio.DailyNotes.helper.PrivacySettingsManager
import com.haodustudio.DailyNotes.utils.BitmapUtils
import com.haodustudio.DailyNotes.viewModel.viewModels.GlobalViewModel
+import io.sentry.Sentry
+import io.sentry.android.core.SentryAndroid
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -29,6 +32,8 @@ class BaseApplication : Application(), ViewModelStoreOwner {
override val viewModelStore: ViewModelStore
get() = appViewModelStore
+ private var sentryInitialized = false
+
companion object {
lateinit var instance: BaseApplication
private set
@@ -135,6 +140,27 @@ class BaseApplication : Application(), ViewModelStoreOwner {
NOTES_PATH = filesDir.absolutePath + "/notes/"
TEMPLATE_DOWNLOAD_FROM_URI_PATH = filesDir.absolutePath + "/uri_template/"
BACKGROUND_DOWNLOAD_FROM_URI_PATH = filesDir.absolutePath + "/uri_background/"
+
+ updateSentryState(PrivacySettingsManager.isCrashReportingEnabled())
+ }
+
+ fun updateSentryState(enabled: Boolean) {
+ if (enabled) {
+ if (!sentryInitialized) {
+ runCatching {
+ SentryAndroid.init(this)
+ }.onSuccess {
+ sentryInitialized = true
+ }.onFailure {
+ sentryInitialized = false
+ }
+ }
+ } else {
+ if (sentryInitialized) {
+ Sentry.close()
+ sentryInitialized = false
+ }
+ }
}
override fun onTerminate() {
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/helper/PrivacySettingsManager.kt b/app/src/main/java/com/haodustudio/DailyNotes/helper/PrivacySettingsManager.kt
new file mode 100644
index 0000000..ef7f44e
--- /dev/null
+++ b/app/src/main/java/com/haodustudio/DailyNotes/helper/PrivacySettingsManager.kt
@@ -0,0 +1,43 @@
+package com.haodustudio.DailyNotes.helper
+
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.core.content.edit
+import com.haodustudio.DailyNotes.BaseApplication
+
+object PrivacySettingsManager {
+ private const val KEY_CRASH_REPORTING = "privacy_crash_reporting_enabled"
+ private const val KEY_LOCATION = "privacy_location_enabled"
+ private const val KEY_CLOUD_RESOURCES = "privacy_cloud_resources_enabled"
+
+ private val prefs: SharedPreferences by lazy {
+ BaseApplication.instance.getSharedPreferences(
+ BaseApplication.APP_SHARED_PREFERENCES_NAME,
+ Context.MODE_PRIVATE
+ )
+ }
+
+ fun isCrashReportingEnabled(): Boolean = prefs.getBoolean(KEY_CRASH_REPORTING, true)
+
+ fun updateCrashReportingEnabled(enabled: Boolean) {
+ prefs.edit { putBoolean(KEY_CRASH_REPORTING, enabled) }
+ BaseApplication.instance.updateSentryState(enabled)
+ }
+
+ fun isLocationEnabled(): Boolean = prefs.getBoolean(KEY_LOCATION, true)
+
+ fun updateLocationEnabled(enabled: Boolean) {
+ prefs.edit {
+ putBoolean(KEY_LOCATION, enabled)
+ if (!enabled && prefs.getBoolean("app_background_is_weather", false)) {
+ putBoolean("app_background_is_weather", false)
+ }
+ }
+ }
+
+ fun isCloudResourcesEnabled(): Boolean = prefs.getBoolean(KEY_CLOUD_RESOURCES, true)
+
+ fun updateCloudResourcesEnabled(enabled: Boolean) {
+ prefs.edit { putBoolean(KEY_CLOUD_RESOURCES, enabled) }
+ }
+}
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/AboutSoftware.kt b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/AboutSoftware.kt
index 02303b6..2fd0158 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/AboutSoftware.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/AboutSoftware.kt
@@ -9,8 +9,9 @@ import com.haodustudio.DailyNotes.BaseApplication
import com.haodustudio.DailyNotes.R
import com.haodustudio.DailyNotes.databinding.ActivityAboutSoftwareBinding
import com.haodustudio.DailyNotes.helper.makeToast
-import com.haodustudio.DailyNotes.view.activities.ViewImage
import com.haodustudio.DailyNotes.view.activities.base.BaseActivity
+import com.haodustudio.DailyNotes.view.activities.ViewImage
+import com.haodustudio.DailyNotes.view.activities.PrivacySettingsActivity
class AboutSoftware : BaseActivity() {
private val binding by lazy { ActivityAboutSoftwareBinding.inflate(layoutInflater) }
@@ -90,7 +91,7 @@ class AboutSoftware : BaseActivity() {
icon.setImageResource(R.drawable.ic_about_privacy)
root.contentDescription = getString(R.string.about_section_privacy_desc)
root.setOnClickListener {
- makeToast(getString(R.string.about_feature_placeholder))
+ startActivity(Intent(this@AboutSoftware, PrivacySettingsActivity::class.java))
}
}
}
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/BackgroundChooser.kt b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/BackgroundChooser.kt
index 4d05816..eff2abf 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/BackgroundChooser.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/BackgroundChooser.kt
@@ -1,11 +1,8 @@
package com.haodustudio.DailyNotes.view.activities
import android.graphics.Bitmap
-import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
-import android.util.Log
import android.view.LayoutInflater
-import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.ViewModelProvider
@@ -15,142 +12,207 @@ import com.bumptech.glide.request.transition.Transition
import com.haodustudio.DailyNotes.BaseApplication
import com.haodustudio.DailyNotes.R
import com.haodustudio.DailyNotes.databinding.ActivityBackgroundChooserBinding
+import com.haodustudio.DailyNotes.helper.PrivacySettingsManager
import com.haodustudio.DailyNotes.helper.makeToast
-import com.haodustudio.DailyNotes.helper.toBoolean
import com.haodustudio.DailyNotes.model.models.BackgroundList
import com.haodustudio.DailyNotes.utils.FileUtils
+import com.haodustudio.DailyNotes.view.activities.base.BaseActivity
import com.haodustudio.DailyNotes.viewModel.repositories.NetworkRepository
import com.haodustudio.DailyNotes.viewModel.viewModels.GlobalViewModel
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
-class BackgroundChooser : AppCompatActivity() {
+class BackgroundChooser : BaseActivity(noShot = true) {
+
private val binding by lazy { ActivityBackgroundChooserBinding.inflate(layoutInflater) }
- private val appViewModel = ViewModelProvider(
- BaseApplication.instance,
- ViewModelProvider.AndroidViewModelFactory.getInstance(BaseApplication.instance)
- )[GlobalViewModel::class.java]
+ private val appViewModel by lazy {
+ ViewModelProvider(
+ BaseApplication.instance,
+ ViewModelProvider.AndroidViewModelFactory.getInstance(BaseApplication.instance)
+ )[GlobalViewModel::class.java]
+ }
+ private val inflater by lazy { LayoutInflater.from(this) }
+ private val remoteItems = mutableSetOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
-
- val backgrounds = ArrayList()
try {
- backgrounds.add(
- BaseApplication.ASSETS_WEATHER_BACKGROUND_PATH + assets.list(
- FileUtils.removePathSlashAtLast(BaseApplication.ASSETS_WEATHER_BACKGROUND_PATH)
- )!![0]
- )
- backgrounds.addAll(
- assets.list(
- FileUtils.removePathSlashAtLast(BaseApplication.ASSETS_DEFAULT_BACKGROUND_PATH)
- )!!.toMutableList().map {
- BaseApplication.ASSETS_DEFAULT_BACKGROUND_PATH + it
- }
- )
+ renderLocalBackgrounds()
+ loadRemoteBackgroundsIfNeeded()
+ } catch (error: Exception) {
+ error.printStackTrace()
+ makeToast("Load background failure")
+ finish()
+ }
+ }
+
+ private fun renderLocalBackgrounds() {
+ val locationEnabled = PrivacySettingsManager.isLocationEnabled()
+ val locals = mutableListOf()
- for (i in 0 until backgrounds.size) {
- val it = backgrounds[i]
- val view = LayoutInflater.from(this).inflate(R.layout.app_background_item, binding.listFather, false)
- Glide.with(this).load("file:///android_asset/$it").into(
- view.findViewById(R.id.background_image)
+ if (locationEnabled) {
+ val weatherAssets = assets.list(
+ FileUtils.removePathSlashAtLast(BaseApplication.ASSETS_WEATHER_BACKGROUND_PATH)
+ )?.sorted()
+ val weatherItem = weatherAssets?.firstOrNull()
+ if (weatherItem != null) {
+ locals.add(
+ LocalBackground(
+ assetPath = BaseApplication.ASSETS_WEATHER_BACKGROUND_PATH + weatherItem,
+ isWeather = true,
+ displayName = getString(R.string.privacy_weather_option_label)
+ )
)
- val mTv = view.findViewById(R.id.background_name)
- if (i == 0) {
- mTv.text = "随天气变化"
- }else {
- mTv.text = "背景 $i"
- }
+ }
+ } else {
+ makeToast(getString(R.string.privacy_location_disabled_hint))
+ }
- val isWeather = !i.toBoolean()
- view.setOnClickListener { _ ->
- Log.d("BackgroundChooser", "Choose background $it")
- try {
- appViewModel.setAppBackground(isWeather, "file:///android_asset/$it")
- }catch (e: Exception) {
- e.printStackTrace()
- makeToast("Change failure")
- }finally {
- finish()
+ val defaultAssets = assets.list(
+ FileUtils.removePathSlashAtLast(BaseApplication.ASSETS_DEFAULT_BACKGROUND_PATH)
+ )?.filter { it.isNotEmpty() && !it.startsWith(".") }
+ ?.sorted()
+ ?.distinct()
+
+ defaultAssets?.forEachIndexed { index, assetName ->
+ locals.add(
+ LocalBackground(
+ assetPath = BaseApplication.ASSETS_DEFAULT_BACKGROUND_PATH + assetName,
+ isWeather = false,
+ displayName = getString(R.string.privacy_background_option_label, index + 1)
+ )
+ )
+ }
+
+ // 使用 distinctBy 确保没有重复的路径
+ locals.distinctBy { it.assetPath }.forEach { addAssetBackground(it) }
+ }
+
+ private fun addAssetBackground(item: LocalBackground) {
+ val view = inflater.inflate(R.layout.app_background_item, binding.listFather, false)
+ val imageView = view.findViewById(R.id.background_image)
+ val nameView = view.findViewById(R.id.background_name)
+
+ Glide.with(this)
+ .load("file:///android_asset/${item.assetPath}")
+ .into(imageView)
+
+ nameView.text = item.displayName
+
+ view.setOnClickListener {
+ setBackgroundAndFinish(item.isWeather, "file:///android_asset/${item.assetPath}")
+ }
+
+ binding.listFather.addView(view)
+ }
+
+ private fun setBackgroundAndFinish(isWeather: Boolean, path: String) {
+ try {
+ appViewModel.setAppBackground(isWeather, path)
+ } catch (error: Exception) {
+ error.printStackTrace()
+ makeToast("Change failure")
+ } finally {
+ finish()
+ }
+ }
+
+ private fun loadRemoteBackgroundsIfNeeded() {
+ if (!PrivacySettingsManager.isCloudResourcesEnabled()) {
+ makeToast(getString(R.string.privacy_cloud_disabled_hint))
+ return
+ }
+
+ makeToast("加载网络背景")
+ val call = NetworkRepository.getBackgroundListCall()
+ if (call == null) {
+ makeToast("无网络连接")
+ return
+ }
+
+ call.enqueue(object : Callback {
+ override fun onResponse(call: Call, response: Response) {
+ try {
+ val list = response.body()?.getList()?.mapNotNull { BaseApplication.buildServerUrl(it) }
+ if (list.isNullOrEmpty()) {
+ makeToast("无网络连接")
+ return
}
+ FileUtils.makeRootDirectory(BaseApplication.BACKGROUND_DOWNLOAD_FROM_URI_PATH)
+ makeToast("获取成功")
+ list.forEach { downloadRemoteBackground(it) }
+ } catch (error: Exception) {
+ onFailure(call, error)
}
- binding.listFather.addView(view)
}
- makeToast("加载网络背景")
- val call = NetworkRepository.getBackgroundListCall()
- if (call == null) {
+ override fun onFailure(call: Call, t: Throwable) {
+ t.printStackTrace()
makeToast("无网络连接")
- } else {
- call.enqueue(object : Callback {
- override fun onResponse(
- call: Call,
- response: Response
- ) {
+ }
+ })
+ }
+
+ private fun downloadRemoteBackground(uri: String) {
+ Glide.with(this).asBitmap().load(uri)
+ .into(object : SimpleTarget() {
+ override fun onResourceReady(resource: Bitmap, transition: Transition?) {
try {
- val obj = response.body()!!
- val realUriList = obj.getList().mapNotNull { BaseApplication.buildServerUrl(it) }
- if (realUriList.isEmpty()) {
- makeToast("无网络连接")
+ val fileName = extractFileName(uri)
+ if (!remoteItems.add(fileName)) {
return
}
- if (!FileUtils.exists(BaseApplication.BACKGROUND_DOWNLOAD_FROM_URI_PATH)) {
- FileUtils.makeRootDirectory(BaseApplication.BACKGROUND_DOWNLOAD_FROM_URI_PATH)
- }
- makeToast("获取成功")
- realUriList.forEach {
- Glide.with(this@BackgroundChooser).asBitmap().load(it).into(object : SimpleTarget() {
- override fun onResourceReady(
- resource: Bitmap,
- transition: Transition?
- ) {
- try {
- val fileName = it.substring(it.lastIndexOf("/") + 1, it.length)
- val cpPath = cacheDir.absolutePath + '/' + fileName
- FileUtils.saveBitmap(cpPath, resource)
- val view = LayoutInflater.from(this@BackgroundChooser).inflate(R.layout.app_background_item, binding.listFather, false)
- Glide.with(this@BackgroundChooser).load(cpPath).into(view.findViewById(R.id.background_image))
- val mTv = view.findViewById(R.id.background_name)
- mTv.text = "在线背景"
- view.setOnClickListener {
- try {
- val tgPath = BaseApplication.BACKGROUND_DOWNLOAD_FROM_URI_PATH + fileName
- FileUtils.copyFile(cpPath, tgPath)
- appViewModel.setAppBackground(false, tgPath)
- }catch (e: Exception) {
- e.printStackTrace()
- makeToast("Setting error")
- }finally {
- finish()
- }
- }
- binding.listFather.addView(view)
- }catch (e: Exception) {
- e.printStackTrace()
- makeToast("Save bitmap failure")
- }
- }
- } )
- }
- }catch (e: Exception) {
- onFailure(call, e)
+ val cachePath = "${cacheDir.absolutePath}/$fileName"
+ FileUtils.saveBitmap(cachePath, resource)
+ addRemoteBackgroundView(cachePath, fileName)
+ } catch (error: Exception) {
+ error.printStackTrace()
+ makeToast("Save bitmap failure")
}
}
+ })
+ }
+
+ private fun addRemoteBackgroundView(cachePath: String, fileName: String) {
+ val view = inflater.inflate(R.layout.app_background_item, binding.listFather, false)
+ val imageView = view.findViewById(R.id.background_image)
+ val nameView = view.findViewById(R.id.background_name)
- override fun onFailure(call: Call, t: Throwable) {
- t.printStackTrace()
- makeToast("无网络连接")
+ Glide.with(this).load(cachePath).into(imageView)
+ nameView.text = getString(R.string.privacy_background_online_label)
+
+ view.setOnClickListener {
+ try {
+ val targetDir = BaseApplication.BACKGROUND_DOWNLOAD_FROM_URI_PATH
+ if (!FileUtils.exists(targetDir)) {
+ FileUtils.makeRootDirectory(targetDir)
}
+ val targetPath = targetDir + fileName
+ FileUtils.copyFile(cachePath, targetPath)
+ appViewModel.setAppBackground(false, targetPath)
+ } catch (error: Exception) {
+ error.printStackTrace()
+ makeToast("Setting error")
+ } finally {
+ finish()
}
- )
- }
- }catch (e: Exception) {
- e.printStackTrace()
- makeToast("Load background failure")
- finish()
}
+
+ binding.listFather.addView(view)
}
+
+ private fun extractFileName(uri: String): String {
+ val base = uri.substringAfterLast('/')
+ val clean = base.substringBefore('?').substringBefore('#')
+ return if (clean.isNotEmpty()) clean else "background_${System.currentTimeMillis()}.png"
+ }
+
+ private data class LocalBackground(
+ val assetPath: String,
+ val isWeather: Boolean,
+ val displayName: String
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/GuideActivity.kt b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/GuideActivity.kt
index 3ac72a1..231c6e7 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/GuideActivity.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/GuideActivity.kt
@@ -9,6 +9,7 @@ import com.bumptech.glide.Glide
import com.haodustudio.DailyNotes.BaseApplication
import com.haodustudio.DailyNotes.R
import com.haodustudio.DailyNotes.databinding.ActivityGuideBinding
+import com.haodustudio.DailyNotes.helper.PrivacySettingsManager
import com.haodustudio.DailyNotes.helper.makeToast
import com.haodustudio.DailyNotes.model.models.GuideImgList
import com.haodustudio.DailyNotes.utils.NetworkUtils
@@ -28,6 +29,12 @@ class GuideActivity : BaseActivity() {
Glide.with(this).load(R.drawable.ic_cute_loading).into(binding.progressBar)
+ if (!PrivacySettingsManager.isCloudResourcesEnabled()) {
+ makeToast(getString(R.string.privacy_cloud_disabled_hint))
+ finish()
+ return
+ }
+
NetworkUtils.isNetworkOnline(object : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/NoteChangeTemplate.kt b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/NoteChangeTemplate.kt
index 0a9c149..95f1ed1 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/NoteChangeTemplate.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/NoteChangeTemplate.kt
@@ -11,7 +11,9 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import com.haodustudio.DailyNotes.BaseApplication
+import com.haodustudio.DailyNotes.R
import com.haodustudio.DailyNotes.databinding.ActivityNoteChangeTemplateBinding
+import com.haodustudio.DailyNotes.helper.PrivacySettingsManager
import com.haodustudio.DailyNotes.helper.makeToast
import com.haodustudio.DailyNotes.helper.toGson
import com.haodustudio.DailyNotes.model.listener.ChangeNoteDataCallBack
@@ -54,12 +56,15 @@ class NoteChangeTemplate : BaseActivity(), View.OnClickListener {
addTmpView(false, id)
}
- makeToast("获取在线模版")
- val call = NetworkRepository.getTemplateListCall()
- if (call == null) {
- makeToast("无网络连接")
+ if (!PrivacySettingsManager.isCloudResourcesEnabled()) {
+ makeToast(getString(R.string.privacy_cloud_disabled_hint))
} else {
- call.enqueue(object: Callback {
+ makeToast("获取在线模版")
+ val call = NetworkRepository.getTemplateListCall()
+ if (call == null) {
+ makeToast("无网络连接")
+ } else {
+ call.enqueue(object: Callback {
override fun onResponse(call: Call, response: Response) {
try {
FileUtils.makeRootDirectory(BaseApplication.TEMPLATE_DOWNLOAD_FROM_URI_PATH)
@@ -99,7 +104,8 @@ class NoteChangeTemplate : BaseActivity(), View.OnClickListener {
makeToast("无网络连接")
}
- })
+ })
+ }
}
}
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/NoteStickerChooser.kt b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/NoteStickerChooser.kt
index b2030df..105a101 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/NoteStickerChooser.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/NoteStickerChooser.kt
@@ -8,7 +8,9 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import com.haodustudio.DailyNotes.BaseApplication
+import com.haodustudio.DailyNotes.R
import com.haodustudio.DailyNotes.databinding.ActivityNoteStickerChooserBinding
+import com.haodustudio.DailyNotes.helper.PrivacySettingsManager
import com.haodustudio.DailyNotes.helper.makeToast
import com.haodustudio.DailyNotes.model.models.StickerList
import com.haodustudio.DailyNotes.utils.FileUtils
@@ -47,12 +49,15 @@ class NoteStickerChooser : BaseActivity(noShot = true) {
adapter = stickerAdapter
}
- makeToast("加载在线贴纸")
- val call = NetworkRepository.getStickerListCall()
- if (call == null) {
- makeToast("无网络连接")
+ if (!PrivacySettingsManager.isCloudResourcesEnabled()) {
+ makeToast(getString(R.string.privacy_cloud_disabled_hint))
} else {
- call.enqueue(object : Callback {
+ makeToast("加载在线贴纸")
+ val call = NetworkRepository.getStickerListCall()
+ if (call == null) {
+ makeToast("无网络连接")
+ } else {
+ call.enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
try {
response.body().let {
@@ -90,7 +95,8 @@ class NoteStickerChooser : BaseActivity(noShot = true) {
makeToast("无网络连接")
}
- })
+ })
+ }
}
}catch (e: Exception) {
e.printStackTrace()
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/view/activities/PrivacySettingsActivity.kt b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/PrivacySettingsActivity.kt
new file mode 100644
index 0000000..5c2f067
--- /dev/null
+++ b/app/src/main/java/com/haodustudio/DailyNotes/view/activities/PrivacySettingsActivity.kt
@@ -0,0 +1,129 @@
+package com.haodustudio.DailyNotes.view.activities
+
+import android.app.Dialog
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.os.Bundle
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.StringRes
+import com.haodustudio.DailyNotes.R
+import com.haodustudio.DailyNotes.databinding.ActivityPrivacySettingsBinding
+import com.haodustudio.DailyNotes.helper.PrivacySettingsManager
+import com.haodustudio.DailyNotes.helper.makeToast
+import com.haodustudio.DailyNotes.view.activities.base.BaseActivity
+
+class PrivacySettingsActivity : BaseActivity() {
+
+ private val binding by lazy { ActivityPrivacySettingsBinding.inflate(layoutInflater) }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+
+ setupListeners()
+ refreshIndicators()
+ }
+
+ private fun setupListeners() {
+ binding.privacyCardCrash.setOnClickListener {
+ handleSettingClick(PrivacySetting.CRASH_REPORTING)
+ }
+ binding.privacyCardLocation.setOnClickListener {
+ handleSettingClick(PrivacySetting.LOCATION)
+ }
+ binding.privacyCardCloud.setOnClickListener {
+ handleSettingClick(PrivacySetting.CLOUD_RESOURCES)
+ }
+ }
+
+ private fun handleSettingClick(setting: PrivacySetting) {
+ val current = isSettingEnabled(setting)
+ val target = !current
+ showConfirmationDialog(setting, target)
+ }
+
+ private fun showConfirmationDialog(setting: PrivacySetting, targetState: Boolean) {
+ val dialog = Dialog(this)
+ dialog.setContentView(R.layout.dialog_privacy_confirmation)
+ dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ dialog.setCanceledOnTouchOutside(false)
+
+ val titleView = dialog.findViewById(R.id.privacyDialogTitle)
+ val messageView = dialog.findViewById(R.id.privacyDialogMessage)
+ val cancelView = dialog.findViewById(R.id.privacyDialogCancel)
+ val confirmView = dialog.findViewById(R.id.privacyDialogConfirm)
+
+ titleView.text = getString(R.string.privacy_confirm_title)
+ val actionText = getString(
+ if (targetState) R.string.privacy_confirm_enable else R.string.privacy_confirm_disable,
+ getString(setting.titleRes)
+ )
+ messageView.text = buildString {
+ append(actionText)
+ append('\n')
+ append(getString(R.string.privacy_confirm_message))
+ }
+
+ cancelView.setOnClickListener { dialog.dismiss() }
+ confirmView.setOnClickListener {
+ applySetting(setting, targetState)
+ dialog.dismiss()
+ }
+
+ dialog.show()
+ }
+
+ private fun applySetting(setting: PrivacySetting, enabled: Boolean) {
+ when (setting) {
+ PrivacySetting.CRASH_REPORTING -> PrivacySettingsManager.updateCrashReportingEnabled(enabled)
+ PrivacySetting.LOCATION -> PrivacySettingsManager.updateLocationEnabled(enabled)
+ PrivacySetting.CLOUD_RESOURCES -> PrivacySettingsManager.updateCloudResourcesEnabled(enabled)
+ }
+ refreshIndicators()
+ val stateText = if (enabled) R.string.privacy_state_enabled else R.string.privacy_state_disabled
+ makeToast("${getString(setting.titleRes)}:${getString(stateText)}")
+ }
+
+ private fun refreshIndicators() {
+ val crashEnabled = PrivacySettingsManager.isCrashReportingEnabled()
+ val locationEnabled = PrivacySettingsManager.isLocationEnabled()
+ val cloudEnabled = PrivacySettingsManager.isCloudResourcesEnabled()
+
+ updateIndicator(binding.privacyCardCrashIndicator, crashEnabled)
+ updateIndicator(binding.privacyCardLocationIndicator, locationEnabled)
+ updateIndicator(binding.privacyCardCloudIndicator, cloudEnabled)
+
+ binding.privacyCardCrashSubtitle.text = buildSubtitle(R.string.privacy_crash_description, crashEnabled)
+ binding.privacyCardLocationSubtitle.text = buildSubtitle(R.string.privacy_location_description, locationEnabled)
+ binding.privacyCardCloudSubtitle.text = buildSubtitle(R.string.privacy_cloud_description, cloudEnabled)
+ }
+
+ private fun updateIndicator(indicator: ImageView, enabled: Boolean) {
+ indicator.setImageResource(
+ if (enabled) R.drawable.bg_privacy_indicator_on else R.drawable.bg_privacy_indicator_off
+ )
+ }
+
+ private fun isSettingEnabled(setting: PrivacySetting): Boolean = when (setting) {
+ PrivacySetting.CRASH_REPORTING -> PrivacySettingsManager.isCrashReportingEnabled()
+ PrivacySetting.LOCATION -> PrivacySettingsManager.isLocationEnabled()
+ PrivacySetting.CLOUD_RESOURCES -> PrivacySettingsManager.isCloudResourcesEnabled()
+ }
+
+ private fun buildSubtitle(@StringRes descriptionRes: Int, enabled: Boolean): String {
+ val statusText = getString(if (enabled) R.string.privacy_state_enabled else R.string.privacy_state_disabled)
+ return buildString {
+ append(getString(descriptionRes))
+ append('\n')
+ append(statusText)
+ }
+ }
+
+ private enum class PrivacySetting(@StringRes val titleRes: Int) {
+ CRASH_REPORTING(R.string.privacy_crash_title),
+ LOCATION(R.string.privacy_location_title),
+ CLOUD_RESOURCES(R.string.privacy_cloud_title)
+ }
+}
diff --git a/app/src/main/java/com/haodustudio/DailyNotes/viewModel/viewModels/GlobalViewModel.kt b/app/src/main/java/com/haodustudio/DailyNotes/viewModel/viewModels/GlobalViewModel.kt
index 2fb09e7..1e036a8 100644
--- a/app/src/main/java/com/haodustudio/DailyNotes/viewModel/viewModels/GlobalViewModel.kt
+++ b/app/src/main/java/com/haodustudio/DailyNotes/viewModel/viewModels/GlobalViewModel.kt
@@ -7,7 +7,9 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.haodustudio.DailyNotes.BaseApplication
+import com.haodustudio.DailyNotes.R
import com.haodustudio.DailyNotes.applicationScope
+import com.haodustudio.DailyNotes.helper.PrivacySettingsManager
import com.haodustudio.DailyNotes.helper.makeToast
import com.haodustudio.DailyNotes.model.listener.AddNoteCallBack
import com.haodustudio.DailyNotes.model.listener.ChangeNoteDataCallBack
@@ -34,7 +36,7 @@ class GlobalViewModel : ViewModel() {
init {
appBackgroundPath.value = getAppBackgroundPath()
- if (appConfigPre.getBoolean("app_background_is_weather", false)) {
+ if (appConfigPre.getBoolean("app_background_is_weather", false) && PrivacySettingsManager.isLocationEnabled()) {
updateWeather(true)
}
}
@@ -110,6 +112,10 @@ class GlobalViewModel : ViewModel() {
}
fun setAppBackground(isWeather: Boolean, path: String) {
+ if (isWeather && !PrivacySettingsManager.isLocationEnabled()) {
+ makeToast(BaseApplication.instance.getString(R.string.privacy_location_disabled_hint))
+ return
+ }
appConfigPre.edit {
putBoolean("app_background_is_weather", isWeather)
putString("app_background_path", path)
@@ -128,6 +134,9 @@ class GlobalViewModel : ViewModel() {
}
private fun updateWeather(fromCache: Boolean = false) {
+ if (!PrivacySettingsManager.isLocationEnabled()) {
+ return
+ }
if (System.currentTimeMillis() - appConfigPre.getLong("app_background_set_time", Long.MAX_VALUE) >= BaseApplication.WEATHER_REFRESH_TIME || !fromCache) {
// refresh and post change
val call = NetworkRepository.getWeatherCall()
diff --git a/app/src/main/res/drawable/bg_privacy_back_button.xml b/app/src/main/res/drawable/bg_privacy_back_button.xml
new file mode 100644
index 0000000..39cf3e0
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_back_button.xml
@@ -0,0 +1,13 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_privacy_banner.xml b/app/src/main/res/drawable/bg_privacy_banner.xml
new file mode 100644
index 0000000..a7d5e9e
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_banner.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_privacy_card.xml b/app/src/main/res/drawable/bg_privacy_card.xml
new file mode 100644
index 0000000..b91f056
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_card.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_privacy_dialog_button_cancel.xml b/app/src/main/res/drawable/bg_privacy_dialog_button_cancel.xml
new file mode 100644
index 0000000..a3de336
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_dialog_button_cancel.xml
@@ -0,0 +1,13 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_privacy_dialog_button_confirm.xml b/app/src/main/res/drawable/bg_privacy_dialog_button_confirm.xml
new file mode 100644
index 0000000..e07d2e6
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_dialog_button_confirm.xml
@@ -0,0 +1,13 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_privacy_dialog_container.xml b/app/src/main/res/drawable/bg_privacy_dialog_container.xml
new file mode 100644
index 0000000..8ba83a9
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_dialog_container.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_privacy_icon_container.xml b/app/src/main/res/drawable/bg_privacy_icon_container.xml
new file mode 100644
index 0000000..a06a472
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_icon_container.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_privacy_indicator_off.xml b/app/src/main/res/drawable/bg_privacy_indicator_off.xml
new file mode 100644
index 0000000..fc5b59d
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_indicator_off.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_privacy_indicator_on.xml b/app/src/main/res/drawable/bg_privacy_indicator_on.xml
new file mode 100644
index 0000000..296a429
--- /dev/null
+++ b/app/src/main/res/drawable/bg_privacy_indicator_on.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_privacy_cloud.xml b/app/src/main/res/drawable/ic_privacy_cloud.xml
new file mode 100644
index 0000000..3c1f87d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_privacy_cloud.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_privacy_crash.xml b/app/src/main/res/drawable/ic_privacy_crash.xml
new file mode 100644
index 0000000..fb39eae
--- /dev/null
+++ b/app/src/main/res/drawable/ic_privacy_crash.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_privacy_dialog_user.xml b/app/src/main/res/drawable/ic_privacy_dialog_user.xml
new file mode 100644
index 0000000..f982304
--- /dev/null
+++ b/app/src/main/res/drawable/ic_privacy_dialog_user.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_privacy_location.xml b/app/src/main/res/drawable/ic_privacy_location.xml
new file mode 100644
index 0000000..db46c8b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_privacy_location.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/img.png b/app/src/main/res/drawable/img.png
deleted file mode 100644
index 025d7b7..0000000
Binary files a/app/src/main/res/drawable/img.png and /dev/null differ
diff --git a/app/src/main/res/drawable/privacy_banner.png b/app/src/main/res/drawable/privacy_banner.png
new file mode 100644
index 0000000..d9f98c6
Binary files /dev/null and b/app/src/main/res/drawable/privacy_banner.png differ
diff --git a/app/src/main/res/drawable/privacy_banner_placeholder.xml b/app/src/main/res/drawable/privacy_banner_placeholder.xml
new file mode 100644
index 0000000..8914bee
--- /dev/null
+++ b/app/src/main/res/drawable/privacy_banner_placeholder.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/privacy_cloud_download.png b/app/src/main/res/drawable/privacy_cloud_download.png
new file mode 100644
index 0000000..7360174
Binary files /dev/null and b/app/src/main/res/drawable/privacy_cloud_download.png differ
diff --git a/app/src/main/res/drawable/privacy_dialog_close.png b/app/src/main/res/drawable/privacy_dialog_close.png
new file mode 100644
index 0000000..7b7d16f
Binary files /dev/null and b/app/src/main/res/drawable/privacy_dialog_close.png differ
diff --git a/app/src/main/res/drawable/privacy_dialog_yes.png b/app/src/main/res/drawable/privacy_dialog_yes.png
new file mode 100644
index 0000000..73489b5
Binary files /dev/null and b/app/src/main/res/drawable/privacy_dialog_yes.png differ
diff --git a/app/src/main/res/drawable/privacy_location.png b/app/src/main/res/drawable/privacy_location.png
new file mode 100644
index 0000000..d5667ac
Binary files /dev/null and b/app/src/main/res/drawable/privacy_location.png differ
diff --git a/app/src/main/res/layout/activity_privacy_settings.xml b/app/src/main/res/layout/activity_privacy_settings.xml
new file mode 100644
index 0000000..de05cce
--- /dev/null
+++ b/app/src/main/res/layout/activity_privacy_settings.xml
@@ -0,0 +1,306 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_privacy_confirmation.xml b/app/src/main/res/layout/dialog_privacy_confirmation.xml
new file mode 100644
index 0000000..93e46f8
--- /dev/null
+++ b/app/src/main/res/layout/dialog_privacy_confirmation.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3bbde9b..eb68341 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -32,6 +32,31 @@
无网络连接
敬请期待
+ 返回
+ 隐私设置
+ 隐私设置宣传图
+ PRIVACY
+ 我们十分重视用户的个人数据安全和隐私保护,因此我们提供了下列设置选项:
+ 崩溃数据上报
+ 启用该选项后若程序崩溃将自动上报数据到Sentry
+ 位置信息
+ 启用该选项后将允许上报位置信息以使用天气功能
+ 云端资源获取
+ 启用该选项后将允许从服务器获取在线资源
+ 随天气变化
+ 背景 %1$d
+ 在线背景
+ 是否确认更新此项设置?
+ 更新后设置将在重启后立即生效
+ 取消
+ 确定
+ 将启用“%1$s”
+ 将关闭“%1$s”
+ 已启用
+ 已关闭
+ 已关闭位置信息,无法使用随天气变化背景
+ 已关闭云端资源获取
+
贡献者
核心开发成员
大版本开发者
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 19810b2..068c688 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -15,4 +15,54 @@
- 2dp
- @drawable/shape_5dp_corners
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file