Skip to content

Commit

Permalink
[1.45.*] Pre-release merge (#254)
Browse files Browse the repository at this point in the history
  • Loading branch information
tramline-github[bot] authored Jan 27, 2024
2 parents 7ec7652 + fc36f8a commit a1a9056
Show file tree
Hide file tree
Showing 17 changed files with 218 additions and 5 deletions.
1 change: 1 addition & 0 deletions core/model/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ kotlin {
implementation(libs.kotlinx.datetime)
// Require this for `@Immutable` annotation for models
implementation(libs.compose.runtime)
implementation(libs.uuid)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2024 Sasikanth Miriyampalli
*
* 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 dev.sasikanth.rss.reader.core.model.local

import com.benasher44.uuid.Uuid
import kotlinx.datetime.Instant

data class Tag(
val id: Uuid,
val label: String,
val createdAt: Instant,
val updatedAt: Instant,
)
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ xmlutil = "0.86.3"
ktxml = "0.2.3"
uri = "0.0.16"
webview = "1.8.4"
uuid = "0.8.2"

[libraries]
compose_runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose" }
Expand Down Expand Up @@ -108,6 +109,7 @@ xmlutil-serialization = { module = "io.github.pdvrieze.xmlutil:serialization", v
ktxml = { module = "org.kobjects.ktxml:core", version.ref = "ktxml" }
uri = { module = "com.eygraber:uri-kmp", version.ref = "uri" }
webview = { module = "io.github.kevinnzou:compose-webview-multiplatform", version.ref = "webview" }
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }

[plugins]
android_application = { id = "com.android.application", version.ref = "android_gradle_plugin" }
Expand Down
1 change: 1 addition & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ kotlin {
implementation(libs.stately.iso.collections)
implementation(libs.bundles.xmlutil)
api(libs.webview)
implementation(libs.uuid)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ private typealias BookmarkPresenterFactory =
(
ComponentContext,
goBack: () -> Unit,
openPost: (String) -> Unit,
openReaderView: (String) -> Unit,
) -> BookmarksPresenter

private typealias SettingsPresenterFactory =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@
package dev.sasikanth.rss.reader.bookmarks

sealed interface BookmarksEffect

data class OpenLink(val link: String) : BookmarksEffect
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class BookmarksPresenter(
private val rssRepository: RssRepository,
@Assisted componentContext: ComponentContext,
@Assisted private val goBack: () -> Unit,
@Assisted private val openPost: (postLink: String) -> Unit,
@Assisted private val openReaderView: (postLink: String) -> Unit,
) : ComponentContext by componentContext {

private val presenterInstance =
Expand All @@ -63,7 +63,12 @@ class BookmarksPresenter(
fun dispatch(event: BookmarksEvent) {
when (event) {
BookmarksEvent.BackClicked -> goBack()
is BookmarksEvent.OnPostClicked -> openPost(event.post.link)
is BookmarksEvent.OnPostClicked ->
presenterInstance.onPostClicked(
post = event.post,
openReaderView = { openReaderView(it) },
openLink = { presenterInstance.openLink(it) }
)
else -> {
// no-op
}
Expand Down Expand Up @@ -101,6 +106,23 @@ class BookmarksPresenter(
}
}

fun onPostClicked(
post: PostWithMetadata,
openReaderView: (postLink: String) -> Unit,
openLink: (postLink: String) -> Unit
) {
coroutineScope.launch {
val hasPost = rssRepository.hasPost(post.link)
val hasFeed = rssRepository.hasFeed(post.feedLink)

if (hasPost && hasFeed) {
openReaderView(post.link)
} else {
openLink(post.link)
}
}
}

private fun onPostBookmarkClicked(post: PostWithMetadata) {
coroutineScope.launch {
if (rssRepository.hasFeed(post.feedLink)) {
Expand All @@ -123,5 +145,9 @@ class BookmarksPresenter(
override fun onDestroy() {
coroutineScope.cancel()
}

fun openLink(link: String) {
coroutineScope.launch { effects.emit(OpenLink(link)) }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
Expand All @@ -51,13 +52,15 @@ import androidx.compose.ui.unit.dp
import app.cash.paging.compose.collectAsLazyPagingItems
import dev.sasikanth.rss.reader.bookmarks.BookmarksEvent
import dev.sasikanth.rss.reader.bookmarks.BookmarksPresenter
import dev.sasikanth.rss.reader.bookmarks.OpenLink
import dev.sasikanth.rss.reader.components.CompactFloatingActionButton
import dev.sasikanth.rss.reader.home.ui.PostListItem
import dev.sasikanth.rss.reader.platform.LocalLinkHandler
import dev.sasikanth.rss.reader.resources.icons.Bookmarks
import dev.sasikanth.rss.reader.resources.icons.TwineIcons
import dev.sasikanth.rss.reader.resources.strings.LocalStrings
import dev.sasikanth.rss.reader.ui.AppTheme
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch

@Composable
Expand All @@ -73,6 +76,14 @@ internal fun BookmarksScreen(
val layoutDirection = LocalLayoutDirection.current
val linkHandler = LocalLinkHandler.current

LaunchedEffect(Unit) {
bookmarksPresenter.effects.collectLatest { effect ->
when (effect) {
is OpenLink -> coroutineScope.launch { linkHandler.openLink(effect.link) }
}
}
}

Scaffold(
modifier = modifier,
topBar = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2024 Sasikanth Miriyampalli
*
* 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 dev.sasikanth.rss.reader.database

import app.cash.sqldelight.ColumnAdapter
import com.benasher44.uuid.Uuid
import com.benasher44.uuid.uuidFrom

internal object UuidAdapter : ColumnAdapter<Uuid, String> {

override fun decode(databaseValue: String): Uuid {
return uuidFrom(databaseValue)
}

override fun encode(value: Uuid): String {
return value.toString()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import dev.sasikanth.rss.reader.database.DateAdapter
import dev.sasikanth.rss.reader.database.Feed
import dev.sasikanth.rss.reader.database.Post
import dev.sasikanth.rss.reader.database.ReaderDatabase
import dev.sasikanth.rss.reader.database.Tag
import dev.sasikanth.rss.reader.database.UuidAdapter
import dev.sasikanth.rss.reader.di.scopes.AppScope
import me.tatarka.inject.annotations.Provides

Expand All @@ -43,6 +45,12 @@ internal interface DataComponent : SqlDriverPlatformComponent, DataStorePlatform
lastCleanUpAtAdapter = DateAdapter
),
bookmarkAdapter = Bookmark.Adapter(dateAdapter = DateAdapter),
tagAdapter =
Tag.Adapter(
idAdapter = UuidAdapter,
createdAtAdapter = DateAdapter,
updatedAtAdapter = DateAdapter
)
)
}

Expand All @@ -57,4 +65,6 @@ internal interface DataComponent : SqlDriverPlatformComponent, DataStorePlatform

@Provides
fun providesFeedSearchFTSQueries(database: ReaderDatabase) = database.feedSearchFTSQueries

@Provides fun providesTagQueries(database: ReaderDatabase) = database.tagQueries
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
Expand Down Expand Up @@ -71,7 +72,12 @@ internal fun FeaturedPostItem(
) {
val isLargeScreenLayout =
LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Expanded
Box(modifier = Modifier.clip(MaterialTheme.shapes.extraLarge).clickable(onClick = onClick)) {
Box(
modifier =
Modifier.clip(MaterialTheme.shapes.extraLarge)
.clickable(onClick = onClick)
.alpha(if (item.read) 0.65f else 1f)
) {
if (isLargeScreenLayout) {
LargeScreenFeaturedPostItem(
item = item,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
Expand Down Expand Up @@ -106,6 +107,7 @@ internal fun PostsList(
PostListItem(
item = post,
enablePostSource = true,
reduceReadItemAlpha = true,
onClick = { onPostClicked(post) },
onPostBookmarkClick = { onPostBookmarkClick(post) },
onPostCommentsClick = { onPostCommentsClick(post.commentsLink!!) },
Expand All @@ -130,13 +132,15 @@ fun PostListItem(
onClick: () -> Unit,
onPostBookmarkClick: () -> Unit,
onPostCommentsClick: () -> Unit,
onPostSourceClick: () -> Unit
onPostSourceClick: () -> Unit,
reduceReadItemAlpha: Boolean = false
) {
Column(
modifier =
Modifier.clickable(onClick = onClick)
.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Horizontal))
.padding(postListPadding)
.alpha(if (item.read && reduceReadItemAlpha) 0.65f else 1f)
) {
Row(
modifier = Modifier.padding(start = 24.dp, top = 20.dp, end = 24.dp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ class RssRepository(
)
}

suspend fun hasPost(link: String): Boolean {
return withContext(ioDispatcher) { postQueries.hasPost(link).executeAsOne() }
}

suspend fun hasFeed(link: String): Boolean {
return withContext(ioDispatcher) { feedQueries.hasFeed(link).executeAsOne() }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2024 Sasikanth Miriyampalli
*
* 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 dev.sasikanth.rss.reader.repository

import app.cash.sqldelight.coroutines.asFlow
import app.cash.sqldelight.coroutines.mapToList
import com.benasher44.uuid.Uuid
import com.benasher44.uuid.uuid4
import dev.sasikanth.rss.reader.core.model.local.Tag
import dev.sasikanth.rss.reader.database.TagQueries
import dev.sasikanth.rss.reader.di.scopes.AppScope
import dev.sasikanth.rss.reader.util.DispatchersProvider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import kotlinx.datetime.Clock
import me.tatarka.inject.annotations.Inject

@Inject
@AppScope
class TagRepository(
private val dispatchersProvider: DispatchersProvider,
private val tagQueries: TagQueries,
) {

suspend fun createTag(label: String) {
withContext(dispatchersProvider.io) {
val currentInstant = Clock.System.now()

tagQueries.saveTag(
id = uuid4(),
label = label,
createdAt = currentInstant,
updatedAt = currentInstant
)
}
}

suspend fun deleteTag(id: Uuid) = withContext(dispatchersProvider.io) { tagQueries.deleteTag(id) }

suspend fun updatedTag(label: String, id: Uuid) {
withContext(dispatchersProvider.io) { tagQueries.updateTag(label = label, id = id) }
}

fun tags(label: String? = null): Flow<List<Tag>> {
return tagQueries.tags(label.orEmpty(), ::Tag).asFlow().mapToList(dispatchersProvider.io)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ internal fun SearchScreen(searchPresenter: SearchPresenter, modifier: Modifier =
PostListItem(
item = post,
enablePostSource = false,
reduceReadItemAlpha = true,
onClick = { searchPresenter.dispatch(SearchEvent.OnPostClicked(post)) },
onPostBookmarkClick = {
searchPresenter.dispatch(SearchEvent.OnPostBookmarkClick(post))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,6 @@ WHERE feedLink = :feedLink;
post:
SELECT * FROM post
WHERE post.link = :link;

hasPost:
SELECT EXISTS(SELECT 1 FROM post WHERE link = :link);
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import com.benasher44.uuid.Uuid;
import kotlinx.datetime.Instant;

CREATE TABLE tag (
id TEXT AS Uuid NOT NULL PRIMARY KEY,
label TEXT NOT NULL,
createdAt INTEGER AS Instant NOT NULL,
updatedAt INTEGER AS Instant NOT NULL
);

tags:
SELECT * FROM tag WHERE label LIKE :label OR label IS NULL OR label = '';

updateTag:
UPDATE tag SET label = :label WHERE id = :id;

deleteTag:
DELETE FROM tag WHERE id = :id;

saveTag:
INSERT OR IGNORE INTO tag(id, label, createdAt, updatedAt)
VALUES (:id, :label, :createdAt, :updatedAt);

0 comments on commit a1a9056

Please sign in to comment.