Skip to content

Commit

Permalink
Add a BottomNavigationView and the UpdateChecker
Browse files Browse the repository at this point in the history
  • Loading branch information
TheLuckyCoder committed Mar 31, 2021
1 parent 3b1a729 commit 58473e6
Show file tree
Hide file tree
Showing 22 changed files with 333 additions and 196 deletions.
14 changes: 10 additions & 4 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,30 @@ android {
versionName(Versions.App.versionName)

resConfigs("en", "de")

addManifestPlaceholders(mapOf("firebaseDisabled" to true, "crashlyticsEnabled" to false))
}

buildTypes {
getByName("debug") {
addManifestPlaceholders(mapOf("firebaseDisabled" to true, "crashlyticsEnabled" to false))

isCrunchPngs = false
extra.set("enableCrashlytics", false)
extra.set("alwaysUpdateBuildId", false)
}
create("staging") {
initWith(buildTypes.getByName("release"))
versionNameSuffix("-staging")

setApplicationIdSuffix(".debug")
debuggable(true)
proguardFiles("proguard-rules.pro")

signingConfig = signingConfigs.getByName("debug")
}
getByName("release") {
addManifestPlaceholders(mapOf("firebaseDisabled" to false, "crashlyticsEnabled" to true))

minifyEnabled(true)
isShrinkResources = true

proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
Expand Down
4 changes: 2 additions & 2 deletions app/src/debug/google-services.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@
"client_info": {
"mobilesdk_app_id": "FAKEfakeFAKE",
"android_client_info": {
"package_name": "net.theluckycoder.stundenplan.debug"
"package_name": "net.theluckycoder.stundenplan"
}
},
"oauth_client": [
{
"client_id": "FAKEfakeFAKE",
"client_type": 1,
"android_info": {
"package_name": "net.theluckycoder.stundenplan.debug",
"package_name": "net.theluckycoder.stundenplan",
"certificate_hash": "FAKEfakeFAKE"
}
},
Expand Down
12 changes: 10 additions & 2 deletions app/src/main/java/net/theluckycoder/stundenplan/App.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.theluckycoder.stundenplan

import android.app.Application
import android.util.Log
import com.google.firebase.ktx.Firebase
import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
Expand All @@ -12,9 +13,16 @@ class App : Application() {
super.onCreate()

val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 5 * 60 // 5 minutes
minimumFetchIntervalInSeconds = 10 * 60 // 10 minutes
}

Firebase.remoteConfig.setConfigSettingsAsync(configSettings)
Firebase.remoteConfig.also {
it.setConfigSettingsAsync(configSettings)
it.fetchAndActivate().addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.i("RemoteConfig", "Remote Config Fetched Successfully")
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package net.theluckycoder.stundenplan.extensions

import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri

fun Context.browseUrl(url: String): Boolean {
return try {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(url)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}

startActivity(intent)
true
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.theluckycoder.stundenplan.extensions

import android.app.Application
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.view.View
import android.widget.ProgressBar
import androidx.core.content.getSystemService
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel

val AndroidViewModel.app: Application
get() = getApplication()
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package net.theluckycoder.stundenplan.model

data class Timetable(
val type: TimetableType,
val url: String,
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package net.theluckycoder.stundenplan
package net.theluckycoder.stundenplan.model

enum class TimetableType {
HIGH_SCHOOL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package net.theluckycoder.stundenplan.repository

import android.content.Context
import androidx.core.net.toUri
import com.google.firebase.ktx.Firebase
import com.google.firebase.remoteconfig.ktx.get
import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.tonyodev.fetch2.AbstractFetchListener
import com.tonyodev.fetch2.Download
import com.tonyodev.fetch2.Error
Expand All @@ -14,35 +17,54 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.sendBlocking
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.tasks.await
import net.theluckycoder.stundenplan.R
import net.theluckycoder.stundenplan.TimetableType
import net.theluckycoder.stundenplan.model.Timetable
import net.theluckycoder.stundenplan.model.TimetableType
import net.theluckycoder.stundenplan.utils.FirebaseConstants
import net.theluckycoder.stundenplan.utils.NetworkResult
import net.theluckycoder.stundenplan.utils.getConfigKey
import java.io.File

class MainRepository(private val context: Context) {

private fun getNewFile(timetableType: TimetableType): File {
val dir = File(context.cacheDir, timetableType.getConfigKey())
private fun getNewFile(timetable: Timetable): File {
val dir = File(context.cacheDir, timetable.type.getConfigKey())
dir.mkdirs()

val minutes = System.currentTimeMillis() / 1000 / 60
return File(dir, "$minutes.pdf")
val name = timetable.url.substringAfterLast('/')

return File(dir, name)
}

fun doesFileExist(timetable: Timetable): Boolean {
return File(
File(context.cacheDir, timetable.type.getConfigKey()),
timetable.url.substringAfter('/')
).exists()
}

suspend fun getTimetable(timetableType: TimetableType): Timetable {
val remoteConfig = Firebase.remoteConfig

remoteConfig.fetchAndActivate().await()
val pdfUrl = remoteConfig[timetableType.getConfigKey()].asString()

return Timetable(timetableType, pdfUrl)
}

@OptIn(ExperimentalCoroutinesApi::class)
suspend fun downloadPdf(timetableType: TimetableType, url: String) = callbackFlow<NetworkResult> {
val file = getNewFile(timetableType).toUri()
suspend fun downloadPdf(timetable: Timetable) = callbackFlow<NetworkResult> {
val file = getNewFile(timetable).toUri()

val request = Request(url, file).apply {
val request = Request(timetable.url, file).apply {
priority = Priority.HIGH
networkType = NetworkType.ALL
}

val listener = object : AbstractFetchListener() {
override fun onCancelled(download: Download) {
sendBlocking(NetworkResult.Failed(R.string.error_download_failed))
sendBlocking(NetworkResult.Failed(NetworkResult.FailReason.DownloadFailed))
close()
}

Expand All @@ -52,7 +74,7 @@ class MainRepository(private val context: Context) {
}

override fun onError(download: Download, error: Error, throwable: Throwable?) {
sendBlocking(NetworkResult.Failed(R.string.error_download_failed))
sendBlocking(NetworkResult.Failed(NetworkResult.FailReason.DownloadFailed))
close()
}

Expand All @@ -69,11 +91,7 @@ class MainRepository(private val context: Context) {
}
}

val fetch = Fetch.getInstance(
FetchConfiguration.Builder(context)
.setDownloadConcurrentLimit(3)
.build()
)
val fetch = Fetch.getInstance(FetchConfiguration.Builder(context).build())

fetch.addListener(listener)
fetch.enqueue(request, { }) { error -> error.throwable?.let { throw it } }
Expand All @@ -94,7 +112,7 @@ class MainRepository(private val context: Context) {

return files.asSequence()
.filterNotNull()
.sortedDescending()
.sortedByDescending { it.lastModified() }
.firstOrNull()
}

Expand Down
Loading

0 comments on commit 58473e6

Please sign in to comment.