Skip to content

Commit 908435f

Browse files
feat(ui-settings): replace theme banner with custom cropable image
1 parent d8ac0b6 commit 908435f

14 files changed

Lines changed: 139 additions & 8 deletions

File tree

V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ object AppConfig {
197197
const val PREF_CUSTOM_SHEET_BANNER_URI = "custom_sheet_banner_uri"
198198
const val PREF_ACTION_CHANGE_SHEET_BANNER = "action_change_sheet_banner_image"
199199
const val PREF_ACTION_DELETE_SHEET_BANNER = "action_delete_sheet_banner_image"
200+
const val PREF_CUSTOM_THEME_BANNER_URI = "custom_theme_banner_uri"
200201
const val PREF_BANNER_SETTINGS_CHARACTER = "pref_banner_settings_character"
201202
const val PREF_BANNER_SETTINGS_CHARACTER_DEFAULT = "uwu_banner_miku_v2"
202203

V2rayNG/app/src/main/java/com/v2ray/ang/handler/SettingsManager.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ object SettingsManager {
5555
AppConfig.PREF_CUSTOM_SHEET_BANNER_URI,
5656
AppConfig.PREF_PROFILE_BANNER_URI,
5757
AppConfig.PREF_SELECTED_BANNER_URI,
58+
AppConfig.PREF_CUSTOM_THEME_BANNER_URI,
5859
)
5960
bannerKeys.forEach { key ->
6061
preloadBanner(context, MmkvManager.decodeSettingsString(key))

V2rayNG/app/src/main/java/com/v2ray/ang/ui/preference/BannerSettingsPreference.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class BannerSettingsPreference @JvmOverloads constructor(
9494
"uwu_banner_miku_v4" -> R.drawable.uwu_banner_miku_v4
9595
"uwu_banner_miku_super_pack" -> R.drawable.uwu_banner_miku_super_pack
9696
"uwu_banner_miku_v6" -> R.drawable.uwu_banner_miku_v6
97-
else -> R.drawable.uwu_banner_miku_v2
97+
else -> R.drawable.uwu_banner_miku_v6
9898
}
9999
}
100100
}

V2rayNG/app/src/main/java/com/v2ray/ang/ui/preference/CustomBannerPreference.kt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package com.v2ray.ang.ui.preference
22

33
import android.content.Context
4+
import android.net.Uri
45
import android.util.AttributeSet
6+
import android.widget.ImageView
57
import android.widget.TextView
68
import androidx.preference.Preference
79
import androidx.preference.PreferenceViewHolder
10+
import com.bumptech.glide.Glide
11+
import com.bumptech.glide.load.engine.DiskCacheStrategy
12+
import com.v2ray.ang.AppConfig
813
import com.v2ray.ang.R
14+
import com.v2ray.ang.handler.MmkvManager
915

1016
class CustomBannerPreference @JvmOverloads constructor(
1117
context: Context,
@@ -14,10 +20,17 @@ class CustomBannerPreference @JvmOverloads constructor(
1420
defStyleRes: Int = 0
1521
) : Preference(context, attrs, defStyleAttr, defStyleRes) {
1622

23+
var onImageClick: (() -> Unit)? = null
24+
var onImageLongClick: (() -> Unit)? = null
25+
1726
init {
1827
layoutResource = R.layout.uwu_banner_theme
1928
}
2029

30+
fun refresh() {
31+
notifyChanged()
32+
}
33+
2134
override fun onBindViewHolder(holder: PreferenceViewHolder) {
2235
super.onBindViewHolder(holder)
2336

@@ -32,6 +45,30 @@ class CustomBannerPreference @JvmOverloads constructor(
3245
(holder.findViewById(R.id.uwu_package_name_summary) as? TextView)?.text = context.getString(R.string.uwu_package_name)
3346
(holder.findViewById(R.id.uwu_build_date_summary) as? TextView)?.text = context.getString(R.string.uwu_build_date)
3447

48+
val imageView = holder.findViewById(R.id.img_banner_preference) as? ImageView
49+
if (imageView != null) {
50+
val uriString = MmkvManager.decodeSettingsString(AppConfig.PREF_CUSTOM_THEME_BANNER_URI)
51+
if (!uriString.isNullOrBlank()) {
52+
Glide.with(context)
53+
.load(Uri.parse(uriString))
54+
.diskCacheStrategy(DiskCacheStrategy.DATA)
55+
.error(R.drawable.uwu_banner_theme)
56+
.into(imageView)
57+
} else {
58+
Glide.with(context).clear(imageView)
59+
imageView.setImageResource(R.drawable.uwu_banner_theme)
60+
}
61+
}
62+
63+
val imageClickTarget = holder.findViewById(R.id.theme_banner_image_card)
64+
imageClickTarget?.setOnClickListener {
65+
onImageClick?.invoke()
66+
}
67+
imageClickTarget?.setOnLongClickListener {
68+
onImageLongClick?.invoke()
69+
true
70+
}
71+
3572
val clickTarget = holder.findViewById(R.id.onClick)
3673
clickTarget?.setOnClickListener {
3774
this.performClick()

V2rayNG/app/src/main/java/com/v2ray/ang/ui/preference/activity/UiSettingsActivity.kt

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ class UiSettingsActivity : BaseActivity() {
168168
if (uri != null) startCropSelectedBannerActivity(uri)
169169
}
170170

171+
private val pickThemeBannerImage =
172+
registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
173+
if (uri != null) startCropThemeBannerActivity(uri)
174+
}
175+
171176
private val pickCustomFontFile =
172177
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
173178
if (uri == null) return@registerForActivityResult
@@ -212,6 +217,28 @@ class UiSettingsActivity : BaseActivity() {
212217
}
213218
}
214219

220+
private val cropThemeBannerImage =
221+
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
222+
if (result.resultCode == Activity.RESULT_OK && result.data != null) {
223+
val cacheUri = UCrop.getOutput(result.data!!) ?: return@registerForActivityResult
224+
lifecycleScope.launch {
225+
try {
226+
val oldUri = MmkvManager.decodeSettingsString(AppConfig.PREF_CUSTOM_THEME_BANNER_URI)
227+
deleteOldFile(oldUri)
228+
val savedUri = saveBannerFile(cacheUri, "theme_banner_")
229+
MmkvManager.encodeSettings(AppConfig.PREF_CUSTOM_THEME_BANNER_URI, savedUri.toString())
230+
SettingsManager.preloadBanner(requireContext(), savedUri.toString())
231+
navigateCheckUpdate?.refresh()
232+
requireContext().toastSuccess(getString(R.string.theme_banner_updated))
233+
} catch (e: Exception) {
234+
e.printStackTrace()
235+
}
236+
}
237+
} else if (result.resultCode == UCrop.RESULT_ERROR) {
238+
UCrop.getError(result.data!!)?.printStackTrace()
239+
}
240+
}
241+
215242
private val cropProfileImage =
216243
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
217244
if (result.resultCode == Activity.RESULT_OK && result.data != null) {
@@ -289,6 +316,32 @@ class UiSettingsActivity : BaseActivity() {
289316
true
290317
}
291318

319+
navigateCheckUpdate?.onImageClick = {
320+
pickThemeBannerImage.launch(
321+
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
322+
)
323+
}
324+
325+
navigateCheckUpdate?.onImageLongClick = {
326+
val savedUri = MmkvManager.decodeSettingsString(AppConfig.PREF_CUSTOM_THEME_BANNER_URI)
327+
if (!savedUri.isNullOrEmpty()) {
328+
MaterialAlertDialogBuilder(requireContext())
329+
.setTitle(R.string.theme_banner_delete_title)
330+
.setIcon(RemixR.drawable.rmx_delete_bin_line)
331+
.setMessage(R.string.theme_banner_delete_summary)
332+
.setPositiveButton(android.R.string.ok) { _, _ ->
333+
lifecycleScope.launch {
334+
deleteOldFile(savedUri)
335+
MmkvManager.encodeSettings(AppConfig.PREF_CUSTOM_THEME_BANNER_URI, "")
336+
navigateCheckUpdate?.refresh()
337+
requireContext().snackbarSuccess(getString(R.string.theme_banner_delete_summary), title = getString(R.string.title_alerter_success))
338+
}
339+
}
340+
.setNegativeButton(android.R.string.cancel, null)
341+
.showBlur()
342+
}
343+
}
344+
292345
appTheme?.setOnPreferenceClickListener {
293346
ThemeColorDialog.show(parentFragmentManager)
294347
true
@@ -902,6 +955,29 @@ class UiSettingsActivity : BaseActivity() {
902955
cropSheetBannerImage.launch(uCrop.getIntent(requireContext()))
903956
}
904957

958+
private fun startCropThemeBannerActivity(sourceUri: Uri) {
959+
val destFile = File(requireContext().cacheDir, "cropped_theme_banner_temp.jpg")
960+
val destUri = Uri.fromFile(destFile)
961+
962+
val displayMetrics = resources.displayMetrics
963+
val screenWidthPx = displayMetrics.widthPixels.toFloat()
964+
val screenHeightPx = displayMetrics.heightPixels.toFloat()
965+
966+
val uCrop = UCrop.of(sourceUri, destUri)
967+
.withAspectRatio(screenWidthPx, screenHeightPx)
968+
.withMaxResultSize(896, 1984)
969+
970+
try {
971+
uCrop.withOptions(UCrop.Options().apply {
972+
setDimmedLayerColor(Color.parseColor("#CC000000"))
973+
setCircleDimmedLayer(false)
974+
setShowCropGrid(true)
975+
setFreeStyleCropEnabled(true)
976+
})
977+
} catch (e: Exception) { e.printStackTrace() }
978+
cropThemeBannerImage.launch(uCrop.getIntent(requireContext()))
979+
}
980+
905981
private fun startCropSelectedBannerActivity(sourceUri: Uri) {
906982
val destFile = File(requireContext().cacheDir, "cropped_selected_banner_temp.jpg")
907983
val destUri = Uri.fromFile(destFile)
-149 KB
Binary file not shown.
161 KB
Loading

V2rayNG/app/src/main/res/layout/uwu_banner_theme.xml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,22 @@
4040
android:layout_height="wrap_content"
4141
android:baselineAligned="false">
4242
<com.google.android.material.card.MaterialCardView
43+
android:id="@+id/theme_banner_image_card"
44+
android:clickable="true"
45+
android:focusable="true"
4346
android:layout_width="140.0dip"
4447
android:layout_height="fill_parent"
4548
app:cardBackgroundColor="#00000000"
4649
app:cardCornerRadius="18.0dip"
4750
app:cardElevation="0.0dip"
48-
app:strokeWidth="0.0dip">
49-
<com.neko.widget.kenburnsview.KenBurnsView
51+
app:strokeWidth="0.0dip"
52+
app:rippleColor="?android:attr/colorControlHighlight">
53+
<ImageView
5054
android:id="@+id/img_banner_preference"
5155
android:layout_width="fill_parent"
5256
android:layout_height="fill_parent"
53-
android:src="@drawable/uwu_banner_image"
54-
android:adjustViewBounds="true" />
57+
android:scaleType="centerCrop"
58+
android:src="@drawable/uwu_banner_theme" />
5559
<LinearLayout
5660
android:background="@android:color/black"
5761
android:layout_width="fill_parent"

V2rayNG/app/src/main/res/values-in/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,9 @@ yang kamu butuhin."</string>
864864
<string name="home_banner_delete_title">Hapus banner beranda kustom</string>
865865
<string name="home_banner_delete_summary">Banner kustom dihapus. Bakal balik pakai banner beranda bawaan</string>
866866
<string name="home_banner_updated">Banner beranda berhasil diupdate.</string>
867+
<string name="theme_banner_updated">Banner berhasil diupdate.</string>
868+
<string name="theme_banner_delete_title">Hapus banner kustom</string>
869+
<string name="theme_banner_delete_summary">Banner kustom dihapus. Bakal balik pakai banner bawaan</string>
867870
<string name="pref_home_banner_height_title">Tinggi banner</string>
868871
<string name="pref_header_top_row_padding_title">Padding atas header</string>
869872

V2rayNG/app/src/main/res/values-ru/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,9 @@
874874
<string name="home_banner_delete_title">Удалить свой баннер главного экрана</string>
875875
<string name="home_banner_delete_summary">Свой баннер удалён. Вместо него будет использоваться баннер главного экрана по умолчанию</string>
876876
<string name="home_banner_updated">Баннер главного экрана успешно обновлён.</string>
877+
<string name="theme_banner_updated">Баннер успешно обновлён.</string>
878+
<string name="theme_banner_delete_title">Удалить свой баннер</string>
879+
<string name="theme_banner_delete_summary">Свой баннер удалён. Вместо него будет использоваться баннер по умолчанию</string>
877880
<string name="pref_home_banner_height_title">Высота баннера</string>
878881
<string name="pref_header_top_row_padding_title">Верхний отступ заголовка</string>
879882

0 commit comments

Comments
 (0)