diff --git a/test-app/android-views/src/main/kotlin/com/example/redwood/testing/android/views/FileStateStore.kt b/test-app/android-views/src/main/kotlin/com/example/redwood/testing/android/views/FileStateStore.kt new file mode 100644 index 0000000000..1ce188f7f3 --- /dev/null +++ b/test-app/android-views/src/main/kotlin/com/example/redwood/testing/android/views/FileStateStore.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2023 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.redwood.testing.android.views + +import app.cash.redwood.treehouse.StateSnapshot +import app.cash.redwood.treehouse.StateStore +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import okio.FileNotFoundException +import okio.FileSystem +import okio.Path + +/** + * Limited state store that creates a new file for each snapshot. + * + * This doesn't implement eviction. + */ +class FileStateStore( + private val json: Json, + private val fileSystem: FileSystem, + private val directory: Path, +) : StateStore { + init { + fileSystem.createDirectories(directory) + // TODO add a mechanism to delete files older than 24 hours + } + + override suspend fun put(id: String, value: StateSnapshot) { + val path = directory / "$id.state" + val tmpPath = directory / "$id.state.tmp" + fileSystem.write(tmpPath) { + writeUtf8(json.encodeToString(value)) + } + fileSystem.atomicMove(tmpPath, path) + } + + override suspend fun get(id: String): StateSnapshot? { + return try { + val path = directory / "$id.state" + fileSystem.read(path) { + json.decodeFromString(readUtf8()) + } + } catch (e: FileNotFoundException) { + null + } + } +} diff --git a/test-app/android-views/src/main/kotlin/com/example/redwood/testing/android/views/TestAppActivity.kt b/test-app/android-views/src/main/kotlin/com/example/redwood/testing/android/views/TestAppActivity.kt index fe5a92b0ec..befa059f2c 100644 --- a/test-app/android-views/src/main/kotlin/com/example/redwood/testing/android/views/TestAppActivity.kt +++ b/test-app/android-views/src/main/kotlin/com/example/redwood/testing/android/views/TestAppActivity.kt @@ -40,6 +40,8 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.flowOf import kotlinx.serialization.json.Json import okhttp3.OkHttpClient +import okio.FileSystem +import okio.Path.Companion.toOkioPath class TestAppActivity : ComponentActivity() { private val scope: CoroutineScope = CoroutineScope(Main) @@ -81,6 +83,11 @@ class TestAppActivity : ComponentActivity() { context = applicationContext, httpClient = httpClient, manifestVerifier = ManifestVerifier.NO_SIGNATURE_CHECKS, + stateStore = FileStateStore( + json = Json, + fileSystem = FileSystem.SYSTEM, + directory = applicationContext.getDir("TreehouseState", MODE_PRIVATE).toOkioPath(), + ), ) val manifestUrlFlow = flowOf("http://10.0.2.2:8080/manifest.zipline.json")