Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search Screen: replace file extensions with post types #55

Merged
merged 1 commit into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ import ru.herobrine1st.e621.api.model.Rating
import ru.herobrine1st.e621.api.model.Tag
import ru.herobrine1st.e621.util.debug

// A simplification of filetype, as there's actually no need to differ between png and jpg
enum class PostType {
IMAGE, // png, jpg
ANIMATION, // gif
VIDEO // webm
}

@Serializable
data class PostsSearchOptions(
val allOf: Set<Tag> = emptySet(),
Expand All @@ -42,8 +49,7 @@ data class PostsSearchOptions(
val orderAscending: Boolean = false,
val rating: Set<Rating> = emptySet(),
val favouritesOf: String? = null, // "favorited_by" in api
val fileType: FileType? = null,
val fileTypeInvert: Boolean = false,
val types: Set<PostType> = emptySet(),
val parent: PostId = PostId.INVALID,
val poolId: PoolId = -1,
) : SearchOptions {
Expand All @@ -56,7 +62,21 @@ data class PostsSearchOptions(
cache += noneOf.map { it.asExcluded }
cache += anyOf.map { it.asAlternative }
cache += optimizeRatingSelection(rating)
fileType?.extension?.let { cache += (if (fileTypeInvert) "-" else "") + "type:" + it }
val fileTypes = types.flatMap {
when (it) {
PostType.IMAGE -> listOf(FileType.PNG, FileType.JPG)
PostType.ANIMATION -> listOf(FileType.GIF)
PostType.VIDEO -> listOf(FileType.WEBM)
}
}
// API does not support OR-ing file types. Alternative tags work, but on common conditions,
// so e.g. `~type:png ~type:jpg ~anthro ~feral` returns posts that have `anthro` despite being a video)
// De Morgan's Law is here to save the day
if (fileTypes.size == 1) {
cache += "filetype:${fileTypes.single().extension}"
} else if (fileTypes.size > 1) {
cache += (FileType.entries - fileTypes - FileType.UNDEFINED).map { "-filetype:${it.extension}" }
}
favouritesOf?.let { cache += "fav:$it" }
(if (orderAscending) order.ascendingApiName else order.apiName)?.let { cache += "order:$it" }
if (parent != PostId.INVALID) cache += "parent:${parent.value}"
Expand Down Expand Up @@ -107,8 +127,7 @@ data class PostsSearchOptions(
orderAscending = orderAscending,
rating = rating.toSet(),
favouritesOf = favouritesOf,
fileType = fileType,
fileTypeInvert = fileTypeInvert,
types = types,
parent = parent,
poolId = poolId
)
Expand All @@ -131,8 +150,7 @@ data class PostsSearchOptions(
var orderAscending: Boolean = false,
var rating: MutableSet<Rating> = mutableSetOf(),
var favouritesOf: String? = null,
var fileType: FileType? = null,
var fileTypeInvert: Boolean = false,
var types: Set<PostType> = mutableSetOf(),
var parent: PostId = PostId.INVALID,
var poolId: PoolId = -1,
) {
Expand All @@ -145,8 +163,7 @@ data class PostsSearchOptions(
orderAscending = orderAscending,
rating = rating,
favouritesOf = favouritesOf,
fileType = fileType,
fileTypeInvert = fileTypeInvert,
types = [email protected],
parent = parent,
poolId = poolId
)
Expand All @@ -162,8 +179,7 @@ data class PostsSearchOptions(
orderAscending = orderAscending,
rating = rating.toMutableSet(),
favouritesOf = favouritesOf,
fileType = fileType,
fileTypeInvert = fileTypeInvert,
types = types,
parent = parent,
poolId = poolId
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ class SearchComponent private constructor(
var orderAscending by mutableStateOf(initialSearchOptions.orderAscending)
val rating = initialSearchOptions.rating.toMutableStateList()
var favouritesOf by mutableStateOf(initialSearchOptions.favouritesOf ?: "")
var fileType by mutableStateOf(initialSearchOptions.fileType)
var fileTypeInvert by mutableStateOf(initialSearchOptions.fileTypeInvert)
val postTypes = initialSearchOptions.types.toMutableStateList()
var parentPostId by mutableIntStateOf(initialSearchOptions.parent.value)
var poolId by mutableIntStateOf(initialSearchOptions.poolId)

Expand Down Expand Up @@ -234,8 +233,7 @@ class SearchComponent private constructor(
orderAscending = orderAscending,
rating = rating.toSet(),
favouritesOf = favouritesOf.ifBlank { null },
fileType = fileType,
fileTypeInvert = fileTypeInvert,
types = postTypes.toSet(),
parent = PostId(parentPostId),
poolId = poolId
)
Expand Down
62 changes: 42 additions & 20 deletions app/src/main/java/ru/herobrine1st/e621/ui/screen/search/Search.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import ru.herobrine1st.e621.R
import ru.herobrine1st.e621.api.AutocompleteSuggestionsAPI
import ru.herobrine1st.e621.api.model.FileType
import ru.herobrine1st.e621.api.model.Order
import ru.herobrine1st.e621.api.model.Rating
import ru.herobrine1st.e621.api.model.Tag
import ru.herobrine1st.e621.api.model.TagAutocompleteSuggestion
import ru.herobrine1st.e621.api.search.PostType
import ru.herobrine1st.e621.api.search.PostsSearchOptions
import ru.herobrine1st.e621.module.CachedDataStore
import ru.herobrine1st.e621.module.DataStoreModule
Expand Down Expand Up @@ -323,30 +323,52 @@ fun Search(
}
item("file type") {
SettingCard(
title = stringResource(R.string.file_type),
title = stringResource(R.string.post_type),
modifier = Modifier.selectableGroup()
) {
ItemSelectionRadioButton(
selected = component.fileType == null,
text = stringResource(R.string.any)
FlowRow(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
component.fileType = null
component.fileTypeInvert = false
}
for (v in FileType.supportedValues()) {
ItemSelectionRadioButton(
selected = v == component.fileType,
text = v.extension
) {
component.fileType = v
CompositionLocalProvider(LocalRippleConfiguration provides null) {
for (type in PostType.entries) {
val selected = type in component.postTypes
FilterChip(
selected = selected,
onClick = {
if (selected)
component.postTypes.remove(type)
else
component.postTypes.add(type)
// Do not force any behavior: users are free to select all
// or select none as it is the same
},
label = {
Text(
when (type) {
PostType.IMAGE -> stringResource(R.string.post_type_image)
PostType.ANIMATION -> stringResource(R.string.post_type_animation)
PostType.VIDEO -> stringResource(R.string.post_type_video)
}
)
},
leadingIcon = {
AnimatedVisibility(
visible = selected,
enter = fadeIn() + expandIn(expandFrom = Alignment.CenterStart),
exit = shrinkOut(shrinkTowards = Alignment.CenterStart) + fadeOut(),
) {
Icon(
Icons.Default.Check,
null,
modifier = Modifier.size(FilterChipDefaults.IconSize)
)
}
}
)
}
}
}
ItemSelectionCheckbox(
checked = component.fileTypeInvert,
text = stringResource(R.string.file_type_invert_selection)
) {
component.fileTypeInvert = it
}
}
}
item("favourites of") {
Expand Down
6 changes: 4 additions & 2 deletions app/src/main/res/values-ru-rRU/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@
<string name="proxy_port">Порт</string>
<string name="proxy_username">Имя пользователя</string>
<string name="proxy_password">Пароль</string>
<string name="file_type">Тип файла</string>
<string name="file_type_invert_selection">Исключить</string>
<string name="post_type">Тип публикации</string>
<string name="wiki_page_not_found">К сожалению, данной вики-страницы не существует. Возможно, она еще не была создана.</string>
<string name="screen_settings_blacklist_entry">Запись чёрного списка</string>
<string name="create_new_fab">Создать</string>
Expand Down Expand Up @@ -170,4 +169,7 @@
<string name="about_build_info">Информация о сборке</string>
<string name="about_build_info_content">"Версия: %1$s\nТип сборки: %2$s\nUser-Agent: %3$s"</string>
<string name="blacklist_fetch_error">Не удалось получить чёрный список из аккаунта</string>
<string name="post_type_image">Изображение</string>
<string name="post_type_video">Видео</string>
<string name="post_type_animation">Анимация</string>
</resources>
6 changes: 4 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ You should have received a copy of the GNU General Public License along with thi
<string name="proxy_port">Port</string>
<string name="proxy_username">Username</string>
<string name="proxy_password">Password</string>
<string name="file_type">File type</string>
<string name="file_type_invert_selection">Exclude</string>
<string name="post_type">Post type</string>
<string name="wiki_page_not_found">"There\'s no such wiki page&lt;br /&gt;It may not have been created yet"</string>
<string name="screen_settings_blacklist_entry">Blacklist entry</string>
<string name="create_new_fab">New</string>
Expand Down Expand Up @@ -170,4 +169,7 @@ You should have received a copy of the GNU General Public License along with thi
<string name="about_build_info_content">"Version: %1$s\nBuild type: %2$s\nUser-Agent: %3$s"</string>
<string name="blacklist_fetch_error">Couldn\'t fetch blacklist from user account</string>
<string name="contributor_tags">Contributor</string>
<string name="post_type_image">Image</string>
<string name="post_type_video">Video</string>
<string name="post_type_animation">Animation</string>
</resources>
Loading