Skip to content

Commit 729b6b7

Browse files
committed
Add preferences options
- Skip bottom sheet link preview - Select modules when bottom sheet is skipped - Clear device clipboard - Open copied link in browser
1 parent c63bd59 commit 729b6b7

17 files changed

Lines changed: 361 additions & 12 deletions

app/src/main/java/com/wstxda/clippy/activity/ClipboardLinkActivity.kt

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
package com.wstxda.clippy.activity
22

3+
import android.content.ClipData
4+
import android.content.ClipboardManager
5+
import android.content.Intent
36
import android.os.Bundle
47
import android.view.View
8+
import androidx.core.content.getSystemService
9+
import androidx.core.net.toUri
510
import androidx.lifecycle.lifecycleScope
611
import com.wstxda.clippy.R
12+
import com.wstxda.clippy.cleaner.data.UrlCleaningModule
713
import com.wstxda.clippy.cleaner.processor.LinkProcessor
14+
import com.wstxda.clippy.logic.PreferenceHelper
815
import com.wstxda.clippy.ui.component.LinkCleanerBottomSheet
916
import com.wstxda.clippy.utils.Constants
1017
import com.wstxda.clippy.utils.Intents.getSharedLink
1118
import kotlinx.coroutines.Dispatchers
19+
import kotlinx.coroutines.async
20+
import kotlinx.coroutines.awaitAll
1221
import kotlinx.coroutines.launch
1322
import kotlinx.coroutines.withContext
1423

1524
abstract class ClipboardLinkActivity : BaseActivity() {
1625

1726
protected abstract val cleanLinks: Boolean
27+
private val preferenceHelper by lazy { PreferenceHelper(this) }
1828

1929
override fun onCreate(savedInstanceState: Bundle?) {
2030
super.onCreate(savedInstanceState)
@@ -52,7 +62,62 @@ abstract class ClipboardLinkActivity : BaseActivity() {
5262
return@launch
5363
}
5464

55-
showLinkCleanerBottomSheet(validUrls)
65+
val skipDialog = preferenceHelper.getBoolean(Constants.SKIP_DIALOG_PREF_KEY, false)
66+
if (skipDialog) {
67+
processAndCopyDirectly(validUrls)
68+
} else {
69+
showLinkCleanerBottomSheet(validUrls)
70+
}
71+
}
72+
}
73+
74+
private fun processAndCopyDirectly(links: List<String>) {
75+
lifecycleScope.launch {
76+
val modules = if (cleanLinks) {
77+
preferenceHelper.getStringSet(
78+
Constants.CLEAN_MODULES_PREF_KEY,
79+
UrlCleaningModule.entries.map { it.name }.toSet()
80+
).map { UrlCleaningModule.valueOf(it) }.toSet()
81+
} else {
82+
emptySet()
83+
}
84+
85+
val processedLinks = withContext(Dispatchers.Default) {
86+
links.map { url ->
87+
async {
88+
LinkProcessor.process(url, modules).cleanedUrl
89+
}
90+
}.awaitAll()
91+
}
92+
93+
val textToCopy = processedLinks.joinToString("\n")
94+
copyToClipboard(textToCopy)
95+
96+
val openInBrowser =
97+
preferenceHelper.getBoolean(Constants.OPEN_IN_BROWSER_PREF_KEY, false)
98+
if (openInBrowser && processedLinks.isNotEmpty()) {
99+
openInBrowser(processedLinks.first())
100+
}
101+
102+
finishWithToast(getString(R.string.copy_success_clipboard))
103+
}
104+
}
105+
106+
private fun copyToClipboard(text: String) {
107+
getSystemService<ClipboardManager>()?.setPrimaryClip(
108+
ClipData.newPlainText("link", text)
109+
)
110+
}
111+
112+
private fun openInBrowser(url: String) {
113+
try {
114+
val intent = Intent(Intent.ACTION_VIEW, url.toUri()).apply {
115+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
116+
}
117+
startActivity(intent)
118+
} catch (_: Exception) {
119+
120+
finishWithToast(getString(R.string.copy_failure_open_browser))
56121
}
57122
}
58123

app/src/main/java/com/wstxda/clippy/cleaner/processor/LinkProcessor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ object LinkProcessor {
4242
}
4343

4444
suspend fun process(
45-
url: String, modules: Set<UrlCleaningModule> = UrlCleaningModule.entries.toSet()
45+
url: String,
46+
modules: Set<UrlCleaningModule> = UrlCleaningModule.entries.toSet()
4647
): LinkProcessorResult {
4748
Logcat.logUrlProcessingStart(Constants.LINK_PROCESSOR, url)
4849

app/src/main/java/com/wstxda/clippy/cleaner/tools/UrlCleaner.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import kotlinx.coroutines.withContext
1515
object UrlCleaner {
1616

1717
suspend fun clean(
18-
url: String, modules: Set<UrlCleaningModule> = UrlCleaningModule.entries.toSet()
18+
url: String,
19+
modules: Set<UrlCleaningModule> = UrlCleaningModule.entries.toSet()
1920
): String = withContext(Dispatchers.IO) {
2021
Logcat.logToolExecution(Constants.URL_CLEANER, "clean")
2122
Logcat.logUrlProcessingStart(Constants.URL_CLEANER, url)
@@ -35,7 +36,8 @@ object UrlCleaner {
3536
}
3637

3738
private suspend fun applyModules(
38-
url: String, modules: Set<UrlCleaningModule>
39+
url: String,
40+
modules: Set<UrlCleaningModule>
3941
): String {
4042
val moduleActions = buildModuleActions(modules)
4143

app/src/main/java/com/wstxda/clippy/fragment/SettingsFragment.kt

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package com.wstxda.clippy.fragment
22

3+
import android.content.ClipData
4+
import android.content.ClipboardManager
35
import android.content.Intent
46
import android.os.Bundle
7+
import android.widget.Toast
8+
import androidx.core.content.getSystemService
59
import androidx.core.net.toUri
610
import androidx.fragment.app.viewModels
711
import androidx.lifecycle.ViewModelProvider
@@ -19,22 +23,25 @@ class SettingsFragment : PreferenceFragmentCompat() {
1923
ViewModelProvider.AndroidViewModelFactory.getInstance(requireActivity().application)
2024
}
2125

22-
private val links = mapOf(
23-
"developer" to "https://github.com/WSTxda",
24-
"github_repository" to "https://github.com/WSTxda/Clippy",
25-
)
26-
2726
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
2827
setPreferencesFromResource(R.xml.settings_preferences, rootKey)
2928
setupPreferences()
3029
}
3130

3231
private fun setupPreferences() {
32+
setupClearClipboardPreference()
3333
setupThemePreference()
3434
setupLibraryPreference()
3535
setupLinkPreferences()
3636
}
3737

38+
private fun setupClearClipboardPreference() {
39+
findPreference<Preference>(Constants.CLEAR_CLIPBOARD_PREF_KEY)?.setOnPreferenceClickListener {
40+
clearClipboard()
41+
true
42+
}
43+
}
44+
3845
private fun setupThemePreference() {
3946
findPreference<ListPreference>(Constants.THEME_PREF_KEY)?.setOnPreferenceChangeListener { _, newValue ->
4047
viewModel.applyTheme(newValue.toString())
@@ -58,4 +65,25 @@ class SettingsFragment : PreferenceFragmentCompat() {
5865
}
5966
}
6067
}
68+
69+
private fun clearClipboard() {
70+
val clipboard = requireContext().getSystemService<ClipboardManager>()
71+
if (clipboard != null) {
72+
clipboard.setPrimaryClip(ClipData.newPlainText("", ""))
73+
74+
// Android 12+
75+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
76+
clipboard.clearPrimaryClip()
77+
}
78+
79+
Toast.makeText(
80+
requireContext(), R.string.clipboard_success_clear, Toast.LENGTH_SHORT
81+
).show()
82+
}
83+
}
84+
85+
private val links = mapOf(
86+
"developer" to "https://github.com/WSTxda",
87+
"github_repository" to "https://github.com/WSTxda/Clippy",
88+
)
6189
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.wstxda.clippy.logic
2+
3+
import android.content.Context
4+
import androidx.preference.PreferenceManager
5+
6+
class PreferenceHelper(context: Context) {
7+
private val preferences = PreferenceManager.getDefaultSharedPreferences(context)
8+
9+
fun getBoolean(key: String, defaultValue: Boolean = false): Boolean =
10+
preferences.getBoolean(key, defaultValue)
11+
12+
fun getStringSet(key: String, defaultValue: Set<String>): Set<String> =
13+
preferences.getStringSet(key, defaultValue) ?: defaultValue
14+
15+
}

app/src/main/java/com/wstxda/clippy/ui/component/LinkCleanerBottomSheet.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
1818
import com.google.android.material.bottomsheet.BottomSheetBehavior
1919
import com.google.android.material.bottomsheet.BottomSheetDialog
2020
import com.wstxda.clippy.R
21+
import android.content.Intent
22+
import androidx.core.net.toUri
2123
import com.wstxda.clippy.cleaner.data.UrlCleaningModule
2224
import com.wstxda.clippy.cleaner.data.LinkActionResult
2325
import com.wstxda.clippy.data.LinkProcessState
26+
import com.wstxda.clippy.logic.PreferenceHelper
2427
import com.wstxda.clippy.databinding.BottomSheetLinkItemBinding
2528
import com.wstxda.clippy.ui.adapter.LinkItemAdapter
2629
import com.wstxda.clippy.ui.animator.AnimationBottomSheet
@@ -31,6 +34,7 @@ import kotlinx.coroutines.launch
3134
class LinkCleanerBottomSheet : BaseBottomSheet<BottomSheetLinkItemBinding>() {
3235

3336
private val viewModel: LinkCleanerViewModel by viewModels()
37+
private val preferenceHelper by lazy { PreferenceHelper(requireContext()) }
3438
private val linkAdapter by lazy { LinkItemAdapter() }
3539
private var wasFinishedWithToast: Boolean = false
3640

@@ -144,6 +148,16 @@ class LinkCleanerBottomSheet : BaseBottomSheet<BottomSheetLinkItemBinding>() {
144148
when (result) {
145149
is LinkActionResult.Success -> {
146150
copyToClipboard(result.text)
151+
152+
val openInBrowser =
153+
preferenceHelper.getBoolean(Constants.OPEN_IN_BROWSER_PREF_KEY, false)
154+
if (openInBrowser) {
155+
val firstUrl = result.text.lineSequence().firstOrNull()
156+
if (firstUrl != null) {
157+
openInBrowser(firstUrl)
158+
}
159+
}
160+
147161
finishWithToast(getString(R.string.copy_success_clipboard))
148162
}
149163

@@ -159,6 +173,17 @@ class LinkCleanerBottomSheet : BaseBottomSheet<BottomSheetLinkItemBinding>() {
159173
)
160174
}
161175

176+
private fun openInBrowser(url: String) {
177+
try {
178+
val intent = Intent(Intent.ACTION_VIEW, url.toUri()).apply {
179+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
180+
}
181+
startActivity(intent)
182+
} catch (_: Exception) {
183+
finishWithToast(getString(R.string.copy_failure_open_browser))
184+
}
185+
}
186+
162187
private fun finishWithToast(message: String) {
163188
wasFinishedWithToast = true
164189
onFinishedWithToast(message)

app/src/main/java/com/wstxda/clippy/utils/Constants.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ object Constants {
55
// Preferences keys //
66

77
const val LIBRARY_PREF_KEY = "library"
8+
const val CLEAR_CLIPBOARD_PREF_KEY = "clear_clipboard"
89
const val THEME_PREF_KEY = "select_theme"
10+
const val SKIP_DIALOG_PREF_KEY = "skip_dialog"
11+
const val CLEAN_MODULES_PREF_KEY = "clean_modules"
12+
const val OPEN_IN_BROWSER_PREF_KEY = "open_in_browser"
913

1014
// Theme values //
1115

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:autoMirrored="true"
5+
android:tint="?attr/colorControlNormal"
6+
android:viewportWidth="960"
7+
android:viewportHeight="960">
8+
<path
9+
android:fillColor="@android:color/white"
10+
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L368,120Q381,84 411.5,62Q442,40 480,40Q518,40 548.5,62Q579,84 592,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM320,680L520,680Q537,680 548.5,668.5Q560,657 560,640Q560,623 548.5,611.5Q537,600 520,600L320,600Q303,600 291.5,611.5Q280,623 280,640Q280,657 291.5,668.5Q303,680 320,680ZM320,520L640,520Q657,520 668.5,508.5Q680,497 680,480Q680,463 668.5,451.5Q657,440 640,440L320,440Q303,440 291.5,451.5Q280,463 280,480Q280,497 291.5,508.5Q303,520 320,520ZM320,360L640,360Q657,360 668.5,348.5Q680,337 680,320Q680,303 668.5,291.5Q657,280 640,280L320,280Q303,280 291.5,291.5Q280,303 280,320Q280,337 291.5,348.5Q303,360 320,360ZM501.5,161.5Q510,153 510,140Q510,127 501.5,118.5Q493,110 480,110Q467,110 458.5,118.5Q450,127 450,140Q450,153 458.5,161.5Q467,170 480,170Q493,170 501.5,161.5Z" />
11+
</vector>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:tint="?attr/colorControlNormal"
5+
android:viewportWidth="960"
6+
android:viewportHeight="960">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M200,800Q167,800 143.5,776.5Q120,753 120,720L120,160Q120,127 143.5,103.5Q167,80 200,80L760,80Q793,80 816.5,103.5Q840,127 840,160L840,400Q840,417 828.5,428.5Q817,440 800,440Q783,440 771.5,428.5Q760,417 760,400L760,160Q760,160 760,160Q760,160 760,160L200,160Q200,160 200,160Q200,160 200,160L200,720Q200,720 200,720Q200,720 200,720L300,720Q317,720 328.5,731.5Q340,743 340,760Q340,777 328.5,788.5Q317,800 300,800L200,800ZM200,680Q200,680 200,680Q200,680 200,680Q200,691 200,700.5Q200,710 200,720L200,720Q200,720 200,720Q200,720 200,720L200,160Q200,160 200,160Q200,160 200,160L200,160Q200,160 200,160Q200,160 200,160L200,680ZM280,520L280,600Q280,617 291.5,628.5Q303,640 320,640L324,640Q332,591 359,549.5Q386,508 428,480L320,480Q303,480 291.5,491.5Q280,503 280,520ZM280,280L280,360Q280,377 291.5,388.5Q303,400 320,400L400,400Q417,400 428.5,388.5Q440,377 440,360L440,280Q440,263 428.5,251.5Q417,240 400,240L320,240Q303,240 291.5,251.5Q280,263 280,280ZM560,840Q494,840 447,793Q400,746 400,680Q400,614 447,567Q494,520 560,520L600,520Q617,520 628.5,531.5Q640,543 640,560Q640,577 628.5,588.5Q617,600 600,600L560,600Q527,600 503.5,623.5Q480,647 480,680Q480,713 503.5,736.5Q527,760 560,760L600,760Q617,760 628.5,771.5Q640,783 640,800Q640,817 628.5,828.5Q617,840 600,840L560,840ZM560,400L640,400Q657,400 668.5,388.5Q680,377 680,360L680,280Q680,263 668.5,251.5Q657,240 640,240L560,240Q543,240 531.5,251.5Q520,263 520,280L520,360Q520,377 531.5,388.5Q543,400 560,400ZM600,720Q583,720 571.5,708.5Q560,697 560,680Q560,663 571.5,651.5Q583,640 600,640L760,640Q777,640 788.5,651.5Q800,663 800,680Q800,697 788.5,708.5Q777,720 760,720L600,720ZM800,840L760,840Q743,840 731.5,828.5Q720,817 720,800Q720,783 731.5,771.5Q743,760 760,760L800,760Q833,760 856.5,736.5Q880,713 880,680Q880,647 856.5,623.5Q833,600 800,600L760,600Q743,600 731.5,588.5Q720,577 720,560Q720,543 731.5,531.5Q743,520 760,520L800,520Q866,520 913,566.5Q960,613 960,680Q960,746 913,793Q866,840 800,840Z" />
10+
</vector>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:tint="?attr/colorOnSurfaceVariant"
5+
android:viewportWidth="960"
6+
android:viewportHeight="960">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M200,800Q167,800 143.5,776.5Q120,753 120,720L120,160Q120,127 143.5,103.5Q167,80 200,80L760,80Q793,80 816.5,103.5Q840,127 840,160L840,400Q840,417 828.5,428.5Q817,440 800,440L560,440Q523,440 489.5,450.5Q456,461 427,480L320,480Q303,480 291.5,491.5Q280,503 280,520L280,600Q280,617 291.5,628.5Q303,640 320,640L323,640Q321,650 320.5,659.5Q320,669 320,680Q320,698 323,716.5Q326,735 331,752Q336,770 326.5,785Q317,800 300,800L200,800ZM560,840Q494,840 447,793Q400,746 400,680Q400,614 447,567Q494,520 560,520L600,520Q617,520 628.5,531.5Q640,543 640,560Q640,577 628.5,588.5Q617,600 600,600L560,600Q527,600 503.5,623.5Q480,647 480,680Q480,713 503.5,736.5Q527,760 560,760L600,760Q617,760 628.5,771.5Q640,783 640,800Q640,817 628.5,828.5Q617,840 600,840L560,840ZM600,720Q583,720 571.5,708.5Q560,697 560,680Q560,663 571.5,651.5Q583,640 600,640L760,640Q777,640 788.5,651.5Q800,663 800,680Q800,697 788.5,708.5Q777,720 760,720L600,720ZM800,840L760,840Q743,840 731.5,828.5Q720,817 720,800Q720,783 731.5,771.5Q743,760 760,760L800,760Q833,760 856.5,736.5Q880,713 880,680Q880,647 856.5,623.5Q833,600 800,600L760,600Q743,600 731.5,588.5Q720,577 720,560Q720,543 731.5,531.5Q743,520 760,520L800,520Q866,520 913,566.5Q960,613 960,680Q960,746 913,793Q866,840 800,840ZM280,280L280,360Q280,377 291.5,388.5Q303,400 320,400L400,400Q417,400 428.5,388.5Q440,377 440,360L440,280Q440,263 428.5,251.5Q417,240 400,240L320,240Q303,240 291.5,251.5Q280,263 280,280ZM560,400L640,400Q657,400 668.5,388.5Q680,377 680,360L680,280Q680,263 668.5,251.5Q657,240 640,240L560,240Q543,240 531.5,251.5Q520,263 520,280L520,360Q520,377 531.5,388.5Q543,400 560,400Z" />
10+
</vector>

0 commit comments

Comments
 (0)