Fixed minor bug and added warning text when app does not have sufficient permissions

This commit is contained in:
partisan 2025-06-03 21:13:38 +02:00
parent 042b079723
commit c8ede0d472
7 changed files with 98 additions and 25 deletions

View file

@ -11,8 +11,8 @@ android {
applicationId = "partisan.weforge.xyz.pulse" applicationId = "partisan.weforge.xyz.pulse"
minSdk = 29 minSdk = 29
targetSdk = 34 targetSdk = 34
versionCode = 15 versionCode = 16
versionName = "2.0.1" versionName = "2.0.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }

View file

@ -89,7 +89,9 @@ class ContactsFragment : Fragment() {
} }
private fun getContacts(): List<ContactEntry> { private fun getContacts(): List<ContactEntry> {
val results = mutableListOf<ContactEntry>()
val resolver: ContentResolver = requireContext().contentResolver val resolver: ContentResolver = requireContext().contentResolver
val projection = arrayOf( val projection = arrayOf(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER ContactsContract.CommonDataKinds.Phone.NUMBER
@ -103,16 +105,16 @@ class ContactsFragment : Fragment() {
"${ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME} ASC" "${ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME} ASC"
) )
val results = mutableListOf<ContactEntry>()
cursor?.use { cursor?.use {
val nameIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME) val nameIndex = it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val numberIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER) val numberIndex = it.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)
while (it.moveToNext()) { while (it.moveToNext()) {
val name = it.getString(nameIndex) ?: continue val name = it.getString(nameIndex)
val number = it.getString(numberIndex) ?: continue val number = it.getString(numberIndex)
results.add(ContactEntry(name, number)) if (!name.isNullOrBlank() && !number.isNullOrBlank()) {
results.add(ContactEntry(name, number))
}
} }
} }

View file

@ -1,17 +1,20 @@
package partisan.weforge.xyz.pulse package partisan.weforge.xyz.pulse
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Bundle import android.os.Bundle
import android.os.SystemClock import android.os.SystemClock
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import java.util.concurrent.TimeUnit
import nl.dionsegijn.konfetti.core.Party import nl.dionsegijn.konfetti.core.Party
import nl.dionsegijn.konfetti.core.Position import nl.dionsegijn.konfetti.core.Position
import nl.dionsegijn.konfetti.core.emitter.Emitter import nl.dionsegijn.konfetti.core.emitter.Emitter
import nl.dionsegijn.konfetti.xml.KonfettiView import nl.dionsegijn.konfetti.xml.KonfettiView
import java.util.concurrent.TimeUnit
class MainFragment : Fragment() { class MainFragment : Fragment() {
@ -24,9 +27,9 @@ class MainFragment : Fragment() {
} }
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
val view = inflater.inflate(R.layout.fragment_main, container, false) val view = inflater.inflate(R.layout.fragment_main, container, false)
prefs = Preferences(requireContext()) prefs = Preferences(requireContext())
@ -44,14 +47,16 @@ class MainFragment : Fragment() {
if (isNowChecked && SystemClock.elapsedRealtime() - lastConfettiTime > 500) { if (isNowChecked && SystemClock.elapsedRealtime() - lastConfettiTime > 500) {
konfetti.start( konfetti.start(
Party( Party(
emitter = Emitter(duration = 100, TimeUnit.MILLISECONDS).perSecond(100), emitter =
speed = 30f, Emitter(duration = 100, TimeUnit.MILLISECONDS)
maxSpeed = 40f, .perSecond(100),
damping = 0.85f, speed = 30f,
spread = 360, maxSpeed = 40f,
position = Position.Relative(0.5, 0.5) damping = 0.85f,
) spread = 360,
position = Position.Relative(0.5, 0.5)
)
) )
lastConfettiTime = SystemClock.elapsedRealtime() lastConfettiTime = SystemClock.elapsedRealtime()
} }
@ -62,6 +67,49 @@ class MainFragment : Fragment() {
} }
} }
val warningText = view.findViewById<TextView>(R.id.warningText)
val warnings = mutableListOf<String>()
// 1. Check if contacts are available
val contactCursor =
requireContext()
.contentResolver
.query(
android.provider.ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
null,
null,
null
)
if (contactCursor != null) {
contactCursor.use {
if (!it.moveToFirst()) {
warnings.add(getString(R.string.warn_no_contacts))
}
}
} else {
warnings.add(getString(R.string.warn_no_contacts))
}
// 2. Check internet connectivity
if (!hasInternet()) {
warnings.add(getString(R.string.warn_no_internet))
}
// Show warning if needed
if (warnings.isNotEmpty()) {
warningText.text = warnings.joinToString("\n")
warningText.visibility = View.VISIBLE
}
return view return view
} }
private fun hasInternet(): Boolean {
val cm = requireContext().getSystemService(ConnectivityManager::class.java)
val capabilities = cm?.getNetworkCapabilities(cm.activeNetwork) ?: return false
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
} }

View file

@ -127,10 +127,13 @@ class SecretView @JvmOverloads constructor(
com.google.android.material.R.attr.colorPrimaryVariant, com.google.android.material.R.attr.colorPrimaryVariant,
com.google.android.material.R.attr.colorSecondary com.google.android.material.R.attr.colorSecondary
) )
context.obtainStyledAttributes(colorAttrs).use { val ta = context.obtainStyledAttributes(colorAttrs)
playerPaint.color = it.getColor(0, Color.CYAN) try {
enemyPaint.color = it.getColor(0, Color.CYAN) playerPaint.color = ta.getColor(0, Color.CYAN)
colorSecondary = it.getColor(1, Color.GREEN) enemyPaint.color = ta.getColor(0, Color.CYAN)
colorSecondary = ta.getColor(1, Color.GREEN)
} finally {
ta.recycle()
} }
Choreographer.getInstance().postFrameCallback(this) Choreographer.getInstance().postFrameCallback(this)

View file

@ -34,4 +34,17 @@
app:iconGravity="textTop" app:iconGravity="textTop"
app:iconPadding="0dp" app:iconPadding="0dp"
app:cornerRadius="48dp" /> app:cornerRadius="48dp" />
<TextView
android:id="@+id/warningText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="16dp"
android:textColor="@android:color/white"
android:background="#AAFF5252"
android:textSize="14sp"
android:text=""
android:visibility="gone" />
</FrameLayout> </FrameLayout>

View file

@ -47,6 +47,10 @@
<item>Random</item> <item>Random</item>
</string-array> </string-array>
<!-- Missing perms -->
<string name="warn_no_contacts">Unable to access contacts.</string>
<string name="warn_no_internet">No internet connection.</string>
<!-- Donate screen --> <!-- Donate screen -->
<string name="donate_title">Support Pulse Development 💖</string> <string name="donate_title">Support Pulse Development 💖</string>
<string name="donate_description">Pulse is free and open-source. You can support future development through Ko-fi. As a thank-you, donors get special popup animation effects!</string> <string name="donate_description">Pulse is free and open-source. You can support future development through Ko-fi. As a thank-you, donors get special popup animation effects!</string>

View file

@ -0,0 +1,3 @@
v2.0.2
- Added warning text in case the app does not have sufficient permissions
- Fixed a bug related to tapping the Pulse logo in the About section, specific to MIUI