commit
7cc7d5e390
8 changed files with 120 additions and 47 deletions
|
@ -73,7 +73,7 @@ Redirecting outgoing calls to E2EE apps.
|
||||||
|
|
||||||
In the app, search for "Pulse" and install it.
|
In the app, search for "Pulse" and install it.
|
||||||
|
|
||||||
*Pulse uses the IzzyOnDroid repo. Some F-Droid clients, such as F-Droid itself, do not include it by default. Please add the IzzyOnDroid repo: https://apt.izzysoft.de/fdroid/repo*
|
_Pulse uses the IzzyOnDroid repo. Some F-Droid clients, such as F-Droid itself, do not include it by default. Please add the IzzyOnDroid repo: https://apt.izzysoft.de/fdroid/repo_
|
||||||
|
|
||||||
## Using Obtainium
|
## Using Obtainium
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ Go to the [Releases page](https://weforge.xyz/partisan/Pulse/releases) and downl
|
||||||
|
|
||||||
Install it, and you’re done!
|
Install it, and you’re done!
|
||||||
|
|
||||||
*Please note that when installing directly, the app will not receive automatic updates.*
|
_Please note that when installing directly, the app will not receive automatic updates._
|
||||||
|
|
||||||
# Permissions
|
# Permissions
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,18 +105,18 @@ 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)
|
||||||
|
if (!name.isNullOrBlank() && !number.isNullOrBlank()) {
|
||||||
results.add(ContactEntry(name, number))
|
results.add(ContactEntry(name, number))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
||||||
|
@ -45,7 +48,9 @@ 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 =
|
||||||
|
Emitter(duration = 100, TimeUnit.MILLISECONDS)
|
||||||
|
.perSecond(100),
|
||||||
speed = 30f,
|
speed = 30f,
|
||||||
maxSpeed = 40f,
|
maxSpeed = 40f,
|
||||||
damping = 0.85f,
|
damping = 0.85f,
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
3
fastlane/metadata/android/en-US/changelogs/17.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/17.txt
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue