Commit 69945f5c authored by Jonas L.'s avatar Jonas L.

Refactoring

parent aa86b235
......@@ -3,10 +3,10 @@ package de.determapp.android.content
import de.determapp.android.ui.viewer.ProjectSpec
object ProjectLocks {
private val lockMap = HashMap<ProjectSpec, Object>()
private val lockMap = HashMap<ProjectSpec, Any>()
private val lock = Object()
fun getLockObject(spec: ProjectSpec): Object {
fun getLockObject(spec: ProjectSpec): Any {
synchronized(lock) {
val oldEntry = lockMap[spec]
......@@ -21,4 +21,4 @@ object ProjectLocks {
}
}
}
}
\ No newline at end of file
}
......@@ -16,38 +16,33 @@ object DeleteDownloadedProject {
val projectsScheduledForDeletion = MutableLiveData<Set<ProjectSpec>>()
fun deleteDownloadedProjectSync(spec: ProjectSpec, context: Context) {
val db = AppDatabaseInstance.with(context)
val database = AppDatabaseInstance.with(context)
val storage = ContentStorage.with(context)
runOnUiThread(Runnable {
val newScheduledProjects = HashSet<ProjectSpec>()
val currentValue = projectsScheduledForDeletion.value
if (currentValue != null) {
newScheduledProjects.addAll(currentValue)
}
newScheduledProjects.add(spec)
projectsScheduledForDeletion.value = Collections.unmodifiableSet(newScheduledProjects)
projectsScheduledForDeletion.value = Collections.unmodifiableSet(
HashSet(projectsScheduledForDeletion.value ?: emptyList()).apply {
add(spec)
}.toSet()
)
})
synchronized(ProjectLocks.getLockObject(spec)) {
// remove project file
if (spec.type == PackageSource.WebPackageSource) {
val dbEntry = db.packageSourceProjectDao().getByIdSync(spec.projectId)
val dbEntry = database.packageSourceProjectDao().getByIdSync(spec.projectId)
if (dbEntry?.localFilename != null) {
db.packageSourceProjectDao().updateLocalFile(spec.projectId, null, null, null)
database.packageSourceProjectDao().updateLocalFile(spec.projectId, null, null, null)
storage.contentFilesToKeep.remove(dbEntry.localFilename)
File(storage.contentFilesDirectory, dbEntry.localFilename).delete()
}
} else if (spec.type == PackageSource.DownloadedFromLocalNetwork) {
val dbEntry = db.localNetworkProjectDao().getProjectByIdSync(spec.projectId)
val dbEntry = database.localNetworkProjectDao().getProjectByIdSync(spec.projectId)
if (dbEntry != null) {
db.localNetworkProjectDao().removeProjectById(spec.projectId)
database.localNetworkProjectDao().removeProjectById(spec.projectId)
storage.contentFilesToKeep.remove(dbEntry.localFilename)
File(storage.contentFilesDirectory, dbEntry.localFilename).delete()
......@@ -62,10 +57,11 @@ object DeleteDownloadedProject {
runOnUiThread(Runnable {
lastDeletedProject.value = spec
val newScheduledProjects = HashSet<ProjectSpec>(projectsScheduledForDeletion.value!!)
newScheduledProjects.remove(spec)
projectsScheduledForDeletion.value = Collections.unmodifiableSet(newScheduledProjects)
projectsScheduledForDeletion.value = Collections.unmodifiableSet(
HashSet(projectsScheduledForDeletion.value!!).apply {
remove(spec)
}
)
})
}
}
......
......@@ -2,6 +2,12 @@ package de.determapp.android.content.database
import androidx.room.Database
import androidx.room.RoomDatabase
import de.determapp.android.content.database.dao.DownloadedLocalNetworkProjectDao
import de.determapp.android.content.database.dao.PackageSourceDao
import de.determapp.android.content.database.dao.PackageSourceProjectDao
import de.determapp.android.content.database.item.DownloadedLocalNetworkProject
import de.determapp.android.content.database.item.PackageSource
import de.determapp.android.content.database.item.PackageSourceProject
@Database(
entities = [
......
package de.determapp.android.content.database
package de.determapp.android.content.database.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import de.determapp.android.content.database.item.DownloadedLocalNetworkProject
@Dao
interface DownloadedLocalNetworkProjectDao {
......
package de.determapp.android.content.database
package de.determapp.android.content.database.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import de.determapp.android.content.database.item.PackageSource
@Dao
interface PackageSourceDao {
......
package de.determapp.android.content.database
package de.determapp.android.content.database.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import de.determapp.android.content.database.item.PackageSourceProject
@Dao
interface PackageSourceProjectDao {
......
package de.determapp.android.content.database
package de.determapp.android.content.database.item
import androidx.room.ColumnInfo
import androidx.room.Entity
......
package de.determapp.android.content.database
package de.determapp.android.content.database.item
import androidx.room.ColumnInfo
import androidx.room.Entity
......
package de.determapp.android.content.database
package de.determapp.android.content.database.item
import androidx.room.ColumnInfo
import androidx.room.Entity
......
......@@ -35,17 +35,17 @@ fun streamContentJson(context: Context, request: ContentJsonDownloadRequest): Pr
val downloadUrl = baseUrl!!.resolve(ContentJsonParser.CONTENT_JSON_PATH);
// start request
val response = Http.getClientWithCache(context).newCall(
Http.getClientWithCache(context).newCall(
Request.Builder()
.url(downloadUrl!!)
.build()
).execute()
).execute().use {
response ->
if(!response.isSuccessful) {
throw IOException("request failed")
}
if(!response.isSuccessful) {
throw IOException("request failed")
}
try {
// try to parse response directly
val project = ContentJsonParser.parseProject(JsonReader(response.body()!!.charStream()))
......@@ -61,8 +61,6 @@ fun streamContentJson(context: Context, request: ContentJsonDownloadRequest): Pr
}
return project
} finally {
response.body()!!.close()
}
}
......@@ -72,62 +70,58 @@ fun downloadContentJson(context: Context, request: ContentJsonDownloadRequest):
val contentStorage = ContentStorage.with(context)
// start request
val response = Http.getClientWithCache(context).newCall(
Http.getClientWithCache(context).newCall(
Request.Builder()
.url(downloadUrl!!)
.build()
).execute()
).execute().use {
response ->
if(!response.isSuccessful) {
throw IOException("request failed")
}
if(!response.isSuccessful) {
throw IOException("request failed")
}
// create temp file
val filename = ContentStorage.generateId()
val file = File(contentStorage.contentFilesDirectory, filename)
var success = false
// create temp file
val filename = ContentStorage.generateId()
val file = File(contentStorage.contentFilesDirectory, filename)
var success = false
contentStorage.contentFilesToKeep.add(filename)
contentStorage.contentFilesToKeep.add(filename)
try {
// write response to file
try {
val tempFileSink = Okio.buffer(Okio.sink(file));
// write response to file
Okio.buffer(Okio.sink(file)).use {
tempFileSink ->
try {
tempFileSink.writeAll(response.body()!!.source())
} finally {
tempFileSink.close()
}
} finally {
response.body()!!.source().close()
}
// try to parse response from temp file
val project = ContentJsonParser.parseProject(JsonReader(FileReader(file)))
// try to parse response from temp file
val project = ContentJsonParser.parseProject(JsonReader(FileReader(file)))
// validation
if (project.projectId != request.projectId) {
throw IOException("downloaded package with other id")
}
// validation
if (project.projectId != request.projectId) {
throw IOException("downloaded package with other id")
}
if (request.assertHash != null) {
if (request.assertHash != project.hash) {
throw IOException("downloaded package has other hash than expected");
if (request.assertHash != null) {
if (request.assertHash != project.hash) {
throw IOException("downloaded package has other hash than expected");
}
}
}
success = true
return ContentJsonDownloadResponse(
filename = filename,
project = project,
fileSize = file.length()
);
} finally {
if (!success) {
file.delete()
contentStorage.contentFilesToKeep.remove(filename)
success = true
return ContentJsonDownloadResponse(
filename = filename,
project = project,
fileSize = file.length()
);
} finally {
if (!success) {
file.delete()
contentStorage.contentFilesToKeep.remove(filename)
}
}
}
}
\ No newline at end of file
}
......@@ -7,7 +7,7 @@ import de.determapp.android.content.ContentJsonParser
import de.determapp.android.content.ContentStorage
import de.determapp.android.content.ProjectLocks
import de.determapp.android.content.database.AppDatabaseInstance
import de.determapp.android.content.database.DownloadedLocalNetworkProject
import de.determapp.android.content.database.item.DownloadedLocalNetworkProject
import de.determapp.android.content.projectdata.Project
import de.determapp.android.ui.viewer.PackageSource
import de.determapp.android.ui.viewer.ProjectSpec
......@@ -27,14 +27,14 @@ data class DownloadLocalNetworkContentRequest(
}
fun downloadOrUpdateLocalNetworkContent(context: Context, request: DownloadLocalNetworkContentRequest, progressListener: ProgressListener?) {
val db = AppDatabaseInstance.with(context)
val database = AppDatabaseInstance.with(context)
val contentStorage = ContentStorage.with(context)
val projectSpec = ProjectSpec(request.projectId, PackageSource.DownloadedFromLocalNetwork)
synchronized(ProjectLocks.getLockObject(projectSpec)) {
lateinit var project: Project
val oldDatabaseEntry = db.localNetworkProjectDao().getProjectByIdSync(request.projectId)
val oldDatabaseEntry = database.localNetworkProjectDao().getProjectByIdSync(request.projectId)
if (oldDatabaseEntry == null || oldDatabaseEntry.hash != request.expectedHash) {
// download the current version
......@@ -63,7 +63,7 @@ fun downloadOrUpdateLocalNetworkContent(context: Context, request: DownloadLocal
// save the new project version
if (oldDatabaseEntry == null) {
// create entry
db.localNetworkProjectDao().addProject(
database.localNetworkProjectDao().addProject(
DownloadedLocalNetworkProject(
projectId = request.projectId,
hash = downloadResponse.project.hash,
......@@ -74,7 +74,7 @@ fun downloadOrUpdateLocalNetworkContent(context: Context, request: DownloadLocal
)
} else {
// update entry
db.localNetworkProjectDao().updateProject(
database.localNetworkProjectDao().updateProject(
request.projectId,
downloadResponse.project.hash,
downloadResponse.filename,
......
package de.determapp.android.content.download
import androidx.lifecycle.MutableLiveData
import android.content.Context
import androidx.core.os.CancellationSignal
import androidx.lifecycle.MutableLiveData
import de.determapp.android.Http
import de.determapp.android.content.ContentStorage
import de.determapp.android.content.projectdata.Image
......@@ -73,7 +73,7 @@ fun updateProjectImages(context: Context, baseUrl: String, project: Project, res
}
for (i in 1..numOfThreads) {
Async.network.submit({
Async.network.submit {
try {
while (true) {
if (ownCancellationSignal.isCanceled) {
......@@ -140,7 +140,7 @@ fun updateProjectImages(context: Context, baseUrl: String, project: Project, res
} finally {
countDownLatch.countDown()
}
})
}
}
countDownLatch.await()
......
......@@ -11,23 +11,21 @@ import java.util.*
import kotlin.collections.HashSet
fun getPackageSourceContent(url: String, context: Context): List<PackageSourceEntry> {
val response = Http.getClientWithCache(context).newCall(
Http.getClientWithCache(context).newCall(
Request.Builder()
.url(
HttpUrl.parse(url)!!
.resolve("./determapp_projects.json")!!
)
.build()
).execute()
).execute().use {
response ->
if (!response.isSuccessful) {
throw IOException("request failed")
}
if (!response.isSuccessful) {
throw IOException("request failed")
}
try {
return parsePackageSource(JsonReader(response.body()!!.charStream()))
} finally {
response.body()!!.close()
}
}
......@@ -103,4 +101,4 @@ data class PackageSourceEntry(val projectId: String, val projectUrl: String, val
throw IllegalStateException()
}
}
}
\ No newline at end of file
}
......@@ -2,8 +2,8 @@ package de.determapp.android.content.packagesource
import android.content.Context
import de.determapp.android.content.database.AppDatabaseInstance
import de.determapp.android.content.database.PackageSource
import de.determapp.android.content.database.PackageSourceProject
import de.determapp.android.content.database.item.PackageSource
import de.determapp.android.content.database.item.PackageSourceProject
private val updatePackageSourceProjectsLock = Object()
......
......@@ -14,8 +14,8 @@ private const val LOG_TAG = "UpdatePackageSource"
fun updatePackageSourcesSync(context: Context): UpdatePackageSourcesResult {
synchronized(updatePackageSourcesLock) {
val db = AppDatabaseInstance.with(context).packageSourceDao()
val sources = db.getPackageSourcesSync()
val database = AppDatabaseInstance.with(context).packageSourceDao()
val sources = database.getPackageSourcesSync()
val failedUrls = ArrayList<String>()
val processedUrls = ArrayList<String>()
......@@ -42,7 +42,7 @@ fun updatePackageSourcesSync(context: Context): UpdatePackageSourcesResult {
}
if (failed != source.lastQueryFailed) {
db.update(source.url, failed)
database.update(source.url, failed)
}
}
......
......@@ -4,8 +4,8 @@ import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import de.determapp.android.content.database.AppDatabaseInstance
import de.determapp.android.content.database.DownloadedLocalNetworkProject
import de.determapp.android.content.database.PackageSourceProject
import de.determapp.android.content.database.item.DownloadedLocalNetworkProject
import de.determapp.android.content.database.item.PackageSourceProject
import de.determapp.android.ui.viewer.PackageSource
import java.util.*
......
package de.determapp.android.ui.packagesource
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import de.determapp.android.content.database.PackageSource
import androidx.recyclerview.widget.RecyclerView
import de.determapp.android.content.database.item.PackageSource
import de.determapp.android.databinding.FragmentPackageSourcesListItemBinding
class PackageSourcesAdapter: RecyclerView.Adapter<ViewHolder>() {
......
......@@ -12,7 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import de.determapp.android.R
import de.determapp.android.content.database.AppDatabaseInstance
import de.determapp.android.content.database.PackageSource
import de.determapp.android.content.database.item.PackageSource
import de.determapp.android.content.packagesource.removePackageSource
import de.determapp.android.util.Async
import kotlinx.android.synthetic.main.fragment_package_sources.*
......
......@@ -5,7 +5,7 @@ import android.text.TextUtils
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import de.determapp.android.content.database.AppDatabaseInstance
import de.determapp.android.content.database.DownloadedLocalNetworkProject
import de.determapp.android.content.database.item.DownloadedLocalNetworkProject
import de.determapp.android.localnetwork.ContentDiscovery
import de.determapp.android.service.DownloadLocalNetworkPackageService
import java.util.*
......
......@@ -21,12 +21,12 @@ interface ProgressListener {
fun callProgressListener(progress: Progress, listener: ProgressListener?) {
if (listener != null) {
Async.handler.post({
Async.handler.post {
listener.onProgressChanged(progress)
})
}
}
}
fun runOnUiThread(runnable: Runnable) {
Async.handler.post(runnable);
}
\ No newline at end of file
}
package de.determapp.android.util
import android.os.SystemClock
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import android.os.SystemClock
object LiveDataUtils {
fun <T> valueToLiveData(value: T): LiveData<T> {
......@@ -19,12 +18,12 @@ object LiveDataUtils {
val result = MediatorLiveData<T>()
var hadValue = false
result.addSource(input, {
result.addSource(input) {
if (it != result.value || (!hadValue)) {
hadValue = true
result.value = it
}
})
}
return result
}
......@@ -35,7 +34,7 @@ object LiveDataUtils {
val handler = Async.handler
val result = MediatorLiveData<T>()
result.addSource(input, Observer {
result.addSource(input) {
val now = SystemClock.uptimeMillis()
if (now - lastDelivery > time) {
......@@ -57,7 +56,7 @@ object LiveDataUtils {
handler.postAtTime(nextRunnable, nextDelivery)
}
})
}
return result
}
......
......@@ -5,7 +5,7 @@
<data>
<variable
name="item"
type="de.determapp.android.content.database.PackageSource" />
type="de.determapp.android.content.database.item.PackageSource" />
<import type="android.view.View" />
</data>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment