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