Skip to content

Commit 15157e4

Browse files
committed
DLNA cast & Remove Firebase
1 parent 281b258 commit 15157e4

160 files changed

Lines changed: 3041 additions & 574 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ PlainApp is also a capable standalone app — not just a server:
4343
- **Sound Meter** — measure ambient noise levels in real time
4444

4545
### 🔒 Privacy & Security
46-
- No Firebase Analytics or Messagingcrash reporting (via Firebase Crashlytics) is optional and opt-in
46+
- No Firebase, no third-party SDKszero analytics, no crash reporting to external servers
4747
- Zero data sent to any third-party server
4848
- All traffic between phone and browser is encrypted (TLS + XChaCha20-Poly1305)
4949
- No account registration required
@@ -154,7 +154,7 @@ PlainApp requires Android 9.0 or higher.
154154

155155
## FAQ
156156

157-
[http://docs.plain.icu/faq.html](http://docs.plain.icu/faq.html)
157+
[https://plainapp.app/docs](https://plainapp.app/docs)
158158

159159
## Support
160160

app/build.gradle.kts

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
import java.io.FileInputStream
22
import java.util.Properties
3-
import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension
43
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
54
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
65

76
plugins {
87
id("com.android.application")
9-
id("com.google.gms.google-services")
10-
id("com.google.firebase.crashlytics")
118
id("kotlin-parcelize")
129
id("androidx.room")
1310
id("com.google.devtools.ksp")
@@ -20,45 +17,6 @@ room {
2017
schemaDirectory("$projectDir/schemas")
2118
}
2219

23-
// Auto-generate a placeholder google-services.json if the real one is absent.
24-
// This lets contributors build without Firebase credentials.
25-
// Replace app/google-services.json with your real file to enable Firebase services.
26-
val googleServicesFile = file("google-services.json")
27-
if (!googleServicesFile.exists()) {
28-
googleServicesFile.writeText(
29-
"""
30-
{
31-
"project_info": {
32-
"project_number": "000000000000",
33-
"project_id": "placeholder-project",
34-
"storage_bucket": "placeholder-project.appspot.com"
35-
},
36-
"client": [
37-
{
38-
"client_info": {
39-
"mobilesdk_app_id": "1:000000000000:android:0000000000000000000000",
40-
"android_client_info": { "package_name": "com.ismartcoding.plain" }
41-
},
42-
"oauth_client": [],
43-
"api_key": [{ "current_key": "placeholder" }],
44-
"services": { "appinvite_service": { "other_platform_oauth_client": [] } }
45-
},
46-
{
47-
"client_info": {
48-
"mobilesdk_app_id": "1:000000000000:android:1111111111111111111111",
49-
"android_client_info": { "package_name": "com.ismartcoding.plain.debug" }
50-
},
51-
"oauth_client": [],
52-
"api_key": [{ "current_key": "placeholder" }],
53-
"services": { "appinvite_service": { "other_platform_oauth_client": [] } }
54-
}
55-
],
56-
"configuration_version": "1"
57-
}
58-
""".trimIndent()
59-
)
60-
}
61-
6220
val keystoreProperties = Properties()
6321
rootProject.file("keystore.properties").let {
6422
if (it.exists()) {
@@ -119,9 +77,6 @@ android {
11977
ndk {
12078
debugSymbolLevel = "NONE"
12179
}
122-
configure<CrashlyticsExtension> {
123-
mappingFileUploadEnabled = false
124-
}
12580
buildConfigField("String", "CHANNEL", "\"GITHUB\"")
12681
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
12782
}
@@ -132,9 +87,6 @@ android {
13287
ndk {
13388
debugSymbolLevel = "SYMBOL_TABLE"
13489
}
135-
configure<CrashlyticsExtension> {
136-
mappingFileUploadEnabled = true
137-
}
13890
setProguardFiles(listOf(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"))
13991
}
14092
}
@@ -208,9 +160,6 @@ dependencies {
208160
// https://developer.android.com/jetpack/androidx/releases/navigation
209161
implementation(libs.compose.navigation)
210162

211-
releaseImplementation(platform(libs.firebase.bom))
212-
releaseImplementation(libs.firebase.crashlytics.ktx)
213-
214163
// Media3
215164
implementation(libs.media3.exoplayer)
216165
implementation(libs.media3.datasource)

app/src/main/java/com/ismartcoding/plain/Constants.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object Constants {
66
const val NOTIFICATION_CHANNEL_ID = "default"
77
const val CHAT_NOTIFICATION_CHANNEL_ID = "peer_chat"
88
const val MAX_READABLE_TEXT_FILE_SIZE = 10 * 1024 * 1024 // 10 MB
9-
const val SUPPORT_EMAIL = "ismartcoding@gmail.com"
9+
const val SUPPORT_EMAIL = "support@plainapp.app"
1010
const val LATEST_RELEASE_URL = "https://api.github.com/repos/plainhub/plain-app/releases/latest"
1111
const val ONE_DAY = 24 * 60 * 60L
1212
const val ONE_DAY_MS = ONE_DAY * 1000L
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.ismartcoding.plain
2+
3+
import android.content.Context
4+
import java.io.File
5+
import java.io.PrintWriter
6+
import java.io.StringWriter
7+
import java.time.LocalDateTime
8+
import java.time.format.DateTimeFormatter
9+
10+
object CrashHandler {
11+
private const val CRASH_FILE_NAME = "crash_report.txt"
12+
private val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
13+
14+
fun install(context: Context) {
15+
val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
16+
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
17+
saveCrash(context, throwable)
18+
defaultHandler?.uncaughtException(thread, throwable)
19+
}
20+
}
21+
22+
fun getPendingReport(context: Context): String? {
23+
val file = File(context.filesDir, CRASH_FILE_NAME)
24+
if (!file.exists()) return null
25+
return try {
26+
val content = file.readText()
27+
file.delete()
28+
content
29+
} catch (_: Exception) {
30+
null
31+
}
32+
}
33+
34+
fun getAppLogs(context: Context): String {
35+
val logFile = File(context.filesDir, "logs/latest.log")
36+
if (!logFile.exists()) return ""
37+
return try {
38+
val lines = logFile.readLines()
39+
lines.takeLast(200).joinToString("\n")
40+
} catch (_: Exception) {
41+
""
42+
}
43+
}
44+
45+
private fun saveCrash(context: Context, throwable: Throwable) {
46+
try {
47+
val sw = StringWriter()
48+
throwable.printStackTrace(PrintWriter(sw))
49+
val timestamp = dateFormat.format(LocalDateTime.now())
50+
val report = buildString {
51+
append("Time: $timestamp\n")
52+
append(sw.toString())
53+
}
54+
File(context.filesDir, CRASH_FILE_NAME).writeText(report)
55+
} catch (_: Exception) {}
56+
}
57+
}

app/src/main/java/com/ismartcoding/plain/MainApp.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.ismartcoding.plain.events.PowerConnectedEvent
1717
import com.ismartcoding.plain.events.AppEvents
1818
import com.ismartcoding.plain.events.StartNearbyServiceEvent
1919
import com.ismartcoding.plain.helpers.AppHelper
20+
import com.ismartcoding.plain.preferences.AdbTokenPreference
2021
import com.ismartcoding.plain.preferences.AudioPlayModePreference
2122
import com.ismartcoding.plain.preferences.AutoCheckUpdatePreference
2223
import com.ismartcoding.plain.preferences.CheckUpdateTimePreference
@@ -52,6 +53,8 @@ class MainApp : Application() {
5253

5354
instance = this
5455

56+
CrashHandler.install(this)
57+
5558
SingletonImageLoader.setSafe { context ->
5659
newImageLoader(context)
5760
}
@@ -79,6 +82,7 @@ class MainApp : Application() {
7982
TempData.httpPort = HttpPortPreference.get(preferences)
8083
TempData.httpsPort = HttpsPortPreference.get(preferences)
8184
TempData.audioPlayMode = AudioPlayModePreference.getValue(preferences)
85+
AdbTokenPreference.ensureValueAsync(instance, preferences)
8286
TempData.nearbyDiscoverable = NearbyDiscoverablePreference.getAsync(instance)
8387
val checkUpdateTime = CheckUpdateTimePreference.get(preferences)
8488
val autoCheckUpdate = AutoCheckUpdatePreference.get(preferences)

app/src/main/java/com/ismartcoding/plain/TempData.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ object TempData {
4040
val notificationActions = mutableMapOf<String, Array<out Notification.Action>>()
4141
var audioPlayMode = MediaPlayMode.REPEAT
4242

43+
var adbToken = "" // in-memory cache of the ADB automation token
44+
4345
var nearbyDiscoverable = false
4446

4547
var audioSleepTimerFutureTime = 0L

app/src/main/java/com/ismartcoding/plain/data/DAudio.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import kotlin.time.Instant
66

77
data class DAudio(
88
override var id: String,
9-
val title: String,
9+
override val title: String,
1010
val artist: String,
1111
override val path: String,
1212
override val duration: Long,

app/src/main/java/com/ismartcoding/plain/data/DVideo.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import kotlin.time.Instant
66
@kotlinx.serialization.Serializable
77
data class DVideo(
88
override var id: String,
9-
val title: String,
9+
override val title: String,
1010
override val path: String,
1111
override val duration: Long,
1212
val size: Long,

app/src/main/java/com/ismartcoding/plain/data/IData.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ data class IDData(override var id: String) : IData
99
interface IMedia {
1010
val path: String
1111
val duration: Long
12+
val title: String
1213
}

app/src/main/java/com/ismartcoding/plain/features/dlna/DlnaCommand.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.ismartcoding.plain.features.dlna
22

33
sealed class DlnaCommand {
4-
data class SetUri(val uri: String, val title: String = "") : DlnaCommand()
4+
data class SetUri(val uri: String, val title: String = "", val mediaType: DlnaMediaType = DlnaMediaType.UNKNOWN, val albumArtUri: String = "") : DlnaCommand()
55
data object Play : DlnaCommand()
66
data object Pause : DlnaCommand()
77
data object Stop : DlnaCommand()

0 commit comments

Comments
 (0)