Skip to content

Commit cfc93a8

Browse files
committed
Update
1 parent 1c495e8 commit cfc93a8

File tree

7 files changed

+324
-219
lines changed

7 files changed

+324
-219
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
1818
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
1919
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
20+
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
21+
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
22+
2023
<application
2124
android:name=".PIO"
2225
android:allowBackup="false"

app/src/main/java/com/tool/tree/MainActivity.kt

Lines changed: 87 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
package com.tool.tree
22

3+
import android.Manifest
34
import android.content.ComponentName
45
import android.content.Intent
6+
import android.content.pm.PackageManager
7+
import android.net.Uri
8+
import android.os.Build
59
import android.os.Bundle
610
import android.view.LayoutInflater
711
import android.view.Menu
812
import android.view.MenuItem
9-
import android.widget.CompoundButton
13+
import android.widget.ArrayAdapter
14+
import android.widget.CheckBox
15+
import android.widget.TextView
1016
import android.widget.Toast
1117
import androidx.activity.addCallback
1218
import androidx.appcompat.app.AppCompatActivity
19+
import androidx.appcompat.widget.ListPopupWindow
1320
import androidx.appcompat.widget.Toolbar
21+
import androidx.core.app.ActivityCompat
22+
import androidx.core.content.ContextCompat
1423
import androidx.lifecycle.lifecycleScope
1524
import com.google.android.material.tabs.TabLayout
1625
import com.google.android.material.tabs.TabLayoutMediator
@@ -29,11 +38,6 @@ import com.tool.tree.ui.TabIconHelper
2938
import kotlinx.coroutines.Dispatchers
3039
import kotlinx.coroutines.launch
3140
import kotlinx.coroutines.withContext
32-
import android.widget.TextView
33-
import android.widget.ArrayAdapter
34-
import androidx.appcompat.widget.ListPopupWindow
35-
import android.widget.CheckBox
36-
import android.net.Uri
3741

3842
class MainActivity : AppCompatActivity() {
3943

@@ -47,6 +51,7 @@ class MainActivity : AppCompatActivity() {
4751

4852
private val ACTION_FILE_PATH_CHOOSER = 65400
4953
private val ACTION_FILE_PATH_CHOOSER_INNER = 65300
54+
private val NOTIFICATION_PERMISSION_REQUEST_CODE = 101
5055
private lateinit var adapter: MainPagerAdapter
5156

5257
override fun onCreate(savedInstanceState: Bundle?) {
@@ -58,13 +63,11 @@ class MainActivity : AppCompatActivity() {
5863
setSupportActionBar(findViewById<Toolbar>(R.id.toolbar))
5964
setTitle(R.string.app_name)
6065

61-
progressBarDialog.showDialog(getString(R.string.please_wait))
62-
loadTabs() // Load tab ngay khi vào
66+
// Kiểm tra quyền thông báo dựa trên cài đặt của người dùng
67+
checkNotificationPermission()
6368

64-
val themeConfig = ThemeConfig(applicationContext)
65-
if (themeConfig.getAllowNotificationUI()) {
66-
WakeLockService.startService(applicationContext)
67-
}
69+
progressBarDialog.showDialog(getString(R.string.please_wait))
70+
loadTabs()
6871

6972
onBackPressedDispatcher.addCallback(this) {
7073
startService(Intent(this@MainActivity, WakeLockService::class.java).apply {
@@ -75,9 +78,43 @@ class MainActivity : AppCompatActivity() {
7578
}
7679
}
7780

78-
// ========================
79-
// LOAD TAB
80-
// ========================
81+
private fun checkNotificationPermission() {
82+
val themeConfig = ThemeConfig(this)
83+
// Chỉ xin quyền nếu người dùng đang bật tính năng Thông báo trong cài đặt
84+
if (themeConfig.getAllowNotificationUI()) {
85+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
86+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
87+
ActivityCompat.requestPermissions(
88+
this,
89+
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
90+
NOTIFICATION_PERMISSION_REQUEST_CODE
91+
)
92+
} else {
93+
WakeLockService.startService(applicationContext)
94+
}
95+
} else {
96+
WakeLockService.startService(applicationContext)
97+
}
98+
}
99+
}
100+
101+
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
102+
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
103+
if (requestCode == NOTIFICATION_PERMISSION_REQUEST_CODE) {
104+
val themeConfig = ThemeConfig(this)
105+
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
106+
// Người dùng đồng ý cấp quyền
107+
if (themeConfig.getAllowNotificationUI()) {
108+
WakeLockService.startService(applicationContext)
109+
}
110+
} else {
111+
// Người dùng từ chối: Tắt cấu hình thông báo để lần sau không hỏi nữa
112+
themeConfig.setAllowNotificationUI(false)
113+
Toast.makeText(this, "Notifications have been disabled due to lack of permission.", Toast.LENGTH_SHORT).show()
114+
}
115+
}
116+
}
117+
81118
private fun loadTabs() {
82119
lifecycleScope.launch(Dispatchers.IO) {
83120
val favorites = getItems(krScriptConfig.favoriteConfig)
@@ -94,64 +131,28 @@ class MainActivity : AppCompatActivity() {
94131
binding.viewPager.offscreenPageLimit = 2
95132
}
96133

97-
// Tab Favorites
98134
favorites?.takeIf { it.isNotEmpty() }?.let {
99-
val fragment = ActionListFragment.create(
100-
it,
101-
getKrScriptActionHandler(krScriptConfig.favoriteConfig, true),
102-
null,
103-
ThemeModeState.getThemeMode()
104-
)
105-
if (adapter.getFragment(0) == null) {
106-
adapter.addFragment(fragment, getString(R.string.tab_favorites))
107-
} else {
108-
adapter.replaceFragment(0, fragment)
109-
}
135+
val fragment = ActionListFragment.create(it, getKrScriptActionHandler(krScriptConfig.favoriteConfig, true), null, ThemeModeState.getThemeMode())
136+
if (adapter.getFragment(0) == null) adapter.addFragment(fragment, getString(R.string.tab_favorites))
137+
else adapter.replaceFragment(0, fragment)
110138
}
111139

112-
// Tab Pages
113140
pages?.takeIf { it.isNotEmpty() }?.let {
114-
val fragment = ActionListFragment.create(
115-
it,
116-
getKrScriptActionHandler(krScriptConfig.pageListConfig, false),
117-
null,
118-
ThemeModeState.getThemeMode()
119-
)
120-
if (adapter.getFragment(1) == null) {
121-
adapter.addFragment(fragment, getString(R.string.tab_pages))
122-
} else {
123-
adapter.replaceFragment(1, fragment)
124-
}
141+
val fragment = ActionListFragment.create(it, getKrScriptActionHandler(krScriptConfig.pageListConfig, false), null, ThemeModeState.getThemeMode())
142+
if (adapter.getFragment(1) == null) adapter.addFragment(fragment, getString(R.string.tab_pages))
143+
else adapter.replaceFragment(1, fragment)
125144
}
126145

127-
// Tab 3
128146
tab3Items?.takeIf { it.isNotEmpty() }?.let {
129-
val fragment = ActionListFragment.create(
130-
it,
131-
getKrScriptActionHandler(krScriptConfig.customTab3Config, false),
132-
null,
133-
ThemeModeState.getThemeMode()
134-
)
135-
if (adapter.getFragment(2) == null) {
136-
adapter.addFragment(fragment, getString(R.string.tab_custom3))
137-
} else {
138-
adapter.replaceFragment(2, fragment)
139-
}
147+
val fragment = ActionListFragment.create(it, getKrScriptActionHandler(krScriptConfig.customTab3Config, false), null, ThemeModeState.getThemeMode())
148+
if (adapter.getFragment(2) == null) adapter.addFragment(fragment, getString(R.string.tab_custom3))
149+
else adapter.replaceFragment(2, fragment)
140150
}
141151

142-
// Tab 4
143152
tab4Items?.takeIf { it.isNotEmpty() }?.let {
144-
val fragment = ActionListFragment.create(
145-
it,
146-
getKrScriptActionHandler(krScriptConfig.customTab4Config, false),
147-
null,
148-
ThemeModeState.getThemeMode()
149-
)
150-
if (adapter.getFragment(3) == null) {
151-
adapter.addFragment(fragment, getString(R.string.tab_custom4))
152-
} else {
153-
adapter.replaceFragment(3, fragment)
154-
}
153+
val fragment = ActionListFragment.create(it, getKrScriptActionHandler(krScriptConfig.customTab4Config, false), null, ThemeModeState.getThemeMode())
154+
if (adapter.getFragment(3) == null) adapter.addFragment(fragment, getString(R.string.tab_custom4))
155+
else adapter.replaceFragment(3, fragment)
155156
}
156157

157158
setupTabs()
@@ -167,48 +168,14 @@ class MainActivity : AppCompatActivity() {
167168
val tab4Items = getItems(krScriptConfig.customTab4Config)
168169

169170
withContext(Dispatchers.Main) {
170-
// Reload Favorites
171-
if (!favorites.isNullOrEmpty()) {
172-
(adapter.getFragment(0) as? ActionListFragment)?.updateData(
173-
favorites,
174-
getKrScriptActionHandler(krScriptConfig.favoriteConfig, true),
175-
ThemeModeState.getThemeMode()
176-
)
177-
}
178-
179-
// Reload Pages
180-
if (!pages.isNullOrEmpty()) {
181-
(adapter.getFragment(1) as? ActionListFragment)?.updateData(
182-
pages,
183-
getKrScriptActionHandler(krScriptConfig.pageListConfig, false),
184-
ThemeModeState.getThemeMode()
185-
)
186-
}
187-
188-
// Reload Tab 3
189-
if (!tab3Items.isNullOrEmpty()) {
190-
(adapter.getFragment(2) as? ActionListFragment)?.updateData(
191-
tab3Items,
192-
getKrScriptActionHandler(krScriptConfig.customTab3Config, false),
193-
ThemeModeState.getThemeMode()
194-
)
195-
}
196-
197-
// Reload Tab 4
198-
if (!tab4Items.isNullOrEmpty()) {
199-
(adapter.getFragment(3) as? ActionListFragment)?.updateData(
200-
tab4Items,
201-
getKrScriptActionHandler(krScriptConfig.customTab4Config, false),
202-
ThemeModeState.getThemeMode()
203-
)
204-
}
171+
if (!favorites.isNullOrEmpty()) (adapter.getFragment(0) as? ActionListFragment)?.updateData(favorites, getKrScriptActionHandler(krScriptConfig.favoriteConfig, true), ThemeModeState.getThemeMode())
172+
if (!pages.isNullOrEmpty()) (adapter.getFragment(1) as? ActionListFragment)?.updateData(pages, getKrScriptActionHandler(krScriptConfig.pageListConfig, false), ThemeModeState.getThemeMode())
173+
if (!tab3Items.isNullOrEmpty()) (adapter.getFragment(2) as? ActionListFragment)?.updateData(tab3Items, getKrScriptActionHandler(krScriptConfig.customTab3Config, false), ThemeModeState.getThemeMode())
174+
if (!tab4Items.isNullOrEmpty()) (adapter.getFragment(3) as? ActionListFragment)?.updateData(tab4Items, getKrScriptActionHandler(krScriptConfig.customTab4Config, false), ThemeModeState.getThemeMode())
205175
}
206176
}
207177
}
208178

209-
// ========================
210-
// SETUP TAB LAYOUT
211-
// ========================
212179
private fun setupTabs() {
213180
val tabHelper = TabIconHelper(this)
214181
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
@@ -226,7 +193,7 @@ class MainActivity : AppCompatActivity() {
226193
binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
227194
override fun onTabSelected(tab: TabLayout.Tab) {
228195
tabHelper.updateHighlight(binding.tabLayout, tab.position)
229-
isFavoritesTab = tab.position == 0
196+
isFavoritesTab = (tab.position == 0)
230197
invalidateOptionsMenu()
231198
}
232199
override fun onTabUnselected(tab: TabLayout.Tab) {}
@@ -271,8 +238,7 @@ class MainActivity : AppCompatActivity() {
271238
val page = clickableNode as? PageNode ?: pageNode
272239
val intent = Intent().apply {
273240
component = ComponentName(applicationContext, ActionPage::class.java)
274-
addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
275-
addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
241+
addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or Intent.FLAG_ACTIVITY_NO_HISTORY)
276242
putExtra("page", page)
277243
if (clickableNode is RunnableNode) putExtra("autoRunItemId", clickableNode.key)
278244
}
@@ -299,7 +265,6 @@ class MainActivity : AppCompatActivity() {
299265
this.fileSelectedInterface = fileSelectedInterface
300266
true
301267
} catch (e: Exception) {
302-
Toast.makeText(this, "File picker error: ${e.message}", Toast.LENGTH_SHORT).show()
303268
false
304269
}
305270
}
@@ -344,14 +309,13 @@ class MainActivity : AppCompatActivity() {
344309
private fun showSettingsDialog() {
345310
val layout = LayoutInflater.from(this).inflate(R.layout.dialog_about, null)
346311
val themeConfig = ThemeConfig(this)
312+
313+
// Cấu hình Theme Selector
347314
val themeSelector = layout.findViewById<TextView>(R.id.theme_selector)
348315
val themeNames = listOf(
349-
getString(R.string.theme_system_default),
350-
getString(R.string.theme_dark),
351-
getString(R.string.theme_light),
352-
getString(R.string.theme_wallpaper_system),
353-
getString(R.string.theme_wallpaper_dark),
354-
getString(R.string.theme_wallpaper_light)
316+
getString(R.string.theme_system_default), getString(R.string.theme_dark),
317+
getString(R.string.theme_light), getString(R.string.theme_wallpaper_system),
318+
getString(R.string.theme_wallpaper_dark), getString(R.string.theme_wallpaper_light)
355319
)
356320
themeSelector.text = themeNames[themeConfig.getThemeMode().coerceAtMost(themeNames.size - 1)]
357321
themeSelector.setOnClickListener {
@@ -360,32 +324,32 @@ class MainActivity : AppCompatActivity() {
360324
popup.setAdapter(ArrayAdapter(this, R.layout.kr_spinner_dropdown, themeNames))
361325
popup.setOnItemClickListener { _, _, position, _ ->
362326
themeConfig.setThemeMode(position)
363-
ThemeModeState.switchTheme(this, position)
364327
themeSelector.text = themeNames[position]
365328
popup.dismiss()
366329
}
367330
popup.width = 490
368331
popup.show()
369332
}
370333

334+
// Cấu hình CheckBox Notification
371335
val checkNotification = layout.findViewById<CheckBox>(R.id.notification_ui)
372336
checkNotification.isChecked = themeConfig.getAllowNotificationUI()
373337
checkNotification.setOnCheckedChangeListener { _, isChecked ->
374338
themeConfig.setAllowNotificationUI(isChecked)
339+
// Nếu người dùng chủ động bật lại, thực hiện xin quyền ngay
340+
if (isChecked) {
341+
checkNotificationPermission()
342+
}
375343
}
376344

377-
val appliction_nameText = layout.findViewById<TextView>(R.id.appliction_nameText)
378-
val appliction_authorText = layout.findViewById<TextView>(R.id.appliction_authorText)
379-
val authorUrl = "https://zenlua.github.io/Tool-Tree/website/Information.html"
380-
val engineUrl = "https://github.com/Zenlua/Tool-Tree"
381-
appliction_authorText.setOnClickListener {
382-
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(authorUrl))
383-
startActivity(intent)
345+
// Các liên kết thông tin
346+
layout.findViewById<TextView>(R.id.appliction_authorText).setOnClickListener {
347+
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://zenlua.github.io/Tool-Tree/website/Information.html")))
384348
}
385-
appliction_nameText.setOnClickListener {
386-
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(engineUrl))
387-
startActivity(intent)
349+
layout.findViewById<TextView>(R.id.appliction_nameText).setOnClickListener {
350+
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/Zenlua/Tool-Tree")))
388351
}
352+
389353
DialogHelper.customDialog(this, layout)
390354
}
391-
}
355+
}

0 commit comments

Comments
 (0)