Add Reading tab with Jhanas Guide and Retreat Instructions PDFs
Some checks failed
Build & Release APK / build (push) Has been cancelled
Some checks failed
Build & Release APK / build (push) Has been cancelled
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,7 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
val composeBom = platform("androidx.compose:compose-bom:2024.10.01")
|
val composeBom = platform("androidx.compose:compose-bom:2024.10.01")
|
||||||
implementation(composeBom)
|
implementation(composeBom)
|
||||||
|
implementation("androidx.core:core-ktx:1.13.1")
|
||||||
implementation("androidx.compose.ui:ui")
|
implementation("androidx.compose.ui:ui")
|
||||||
implementation("androidx.compose.material3:material3")
|
implementation("androidx.compose.material3:material3")
|
||||||
implementation("androidx.activity:activity-compose:1.9.3")
|
implementation("androidx.activity:activity-compose:1.9.3")
|
||||||
|
|||||||
@@ -27,6 +27,16 @@
|
|||||||
android:name=".TimerService"
|
android:name=".TimerService"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:foregroundServiceType="mediaPlayback" />
|
android:foregroundServiceType="mediaPlayback" />
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="com.marcus.meditationtimer.files"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
BIN
app/src/main/assets/reading/jhanas-guide.pdf
Normal file
BIN
app/src/main/assets/reading/jhanas-guide.pdf
Normal file
Binary file not shown.
BIN
app/src/main/assets/reading/retreat-instructions.pdf
Normal file
BIN
app/src/main/assets/reading/retreat-instructions.pdf
Normal file
Binary file not shown.
@@ -1,10 +1,14 @@
|
|||||||
package com.marcus.meditationtimer
|
package com.marcus.meditationtimer
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import java.io.File
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
@@ -136,6 +140,7 @@ private fun App() {
|
|||||||
) {
|
) {
|
||||||
Tab(selected = tab == 0, onClick = { tab = 0 }, text = { Text("Timer") })
|
Tab(selected = tab == 0, onClick = { tab = 0 }, text = { Text("Timer") })
|
||||||
Tab(selected = tab == 1, onClick = { tab = 1 }, text = { Text("History") })
|
Tab(selected = tab == 1, onClick = { tab = 1 }, text = { Text("History") })
|
||||||
|
Tab(selected = tab == 2, onClick = { tab = 2 }, text = { Text("Reading") })
|
||||||
}
|
}
|
||||||
when (tab) {
|
when (tab) {
|
||||||
0 -> TimerTab()
|
0 -> TimerTab()
|
||||||
@@ -143,6 +148,7 @@ private fun App() {
|
|||||||
onEditSession = { ratingFor = it },
|
onEditSession = { ratingFor = it },
|
||||||
onOpenToken = { showTokenDialog = true },
|
onOpenToken = { showTokenDialog = true },
|
||||||
)
|
)
|
||||||
|
2 -> ReadingTab()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,6 +436,67 @@ private fun SessionRow(s: Session, onClick: () -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- Reading tab
|
||||||
|
|
||||||
|
private data class Doc(val title: String, val subtitle: String, val asset: String)
|
||||||
|
|
||||||
|
private val DOCS = listOf(
|
||||||
|
Doc("Pragmatic Jhanas Guide", "v4.3", "jhanas-guide.pdf"),
|
||||||
|
Doc("Retreat Instructions", "v6.0.3 · Day 1 & 2", "retreat-instructions.pdf"),
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ReadingTab() {
|
||||||
|
val context = LocalContext.current
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(20.dp)
|
||||||
|
) {
|
||||||
|
DOCS.forEach { doc ->
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable { openPdf(context, doc) }
|
||||||
|
.background(Color.White.copy(alpha = 0.05f), RoundedCornerShape(12.dp))
|
||||||
|
.padding(20.dp)
|
||||||
|
) {
|
||||||
|
Text(doc.title, color = Color.White.copy(alpha = 0.9f), fontSize = 16.sp)
|
||||||
|
Spacer(Modifier.height(4.dp))
|
||||||
|
Text(doc.subtitle, color = Dim, fontSize = 12.sp)
|
||||||
|
}
|
||||||
|
Spacer(Modifier.height(12.dp))
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
"Opens in the system PDF viewer.",
|
||||||
|
color = Dim,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openPdf(context: Context, doc: Doc) {
|
||||||
|
try {
|
||||||
|
val dir = File(context.cacheDir, "reading").apply { mkdirs() }
|
||||||
|
val outFile = File(dir, doc.asset)
|
||||||
|
if (!outFile.exists() || outFile.length() == 0L) {
|
||||||
|
context.assets.open("reading/${doc.asset}").use { input ->
|
||||||
|
outFile.outputStream().use { input.copyTo(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val uri = FileProvider.getUriForFile(context, "${context.packageName}.files", outFile)
|
||||||
|
context.startActivity(
|
||||||
|
Intent(Intent.ACTION_VIEW)
|
||||||
|
.setDataAndType(uri, "application/pdf")
|
||||||
|
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, "Could not open PDF: ${e.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------- Dialogs
|
// ----------------------------------------------------------------- Dialogs
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
4
app/src/main/res/xml/file_paths.xml
Normal file
4
app/src/main/res/xml/file_paths.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<cache-path name="reading" path="reading/" />
|
||||||
|
</paths>
|
||||||
Reference in New Issue
Block a user