From 6a4d2a57f083c8709dda74cacf62e33a1ef43941 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Fri, 20 Oct 2023 17:54:20 +0800 Subject: [PATCH] First pass at label flair for iOS and Android --- android/Omnivore/app/build.gradle | 4 +- .../networking/SavedItemLabelMutations.kt | 6 +- .../omnivore/ui/components/LabelsViewModel.kt | 15 --- .../omnivore/ui/library/LibraryViewModel.kt | 75 ++++++------- .../ui/savedItemViews/SavedItemCard.kt | 105 ++++++++++++++++-- .../app/src/main/res/drawable/flair_feed.xml | 31 ++++++ .../main/res/drawable/flair_newsletter.xml | 16 +++ .../src/main/res/drawable/flair_pinned.xml | 13 +++ .../main/res/drawable/flair_recommended.xml | 16 +++ .../src/main/res/drawable/flaire_favorite.xml | 13 +++ apple/Omnivore.xcodeproj/project.pbxproj | 8 +- .../Views/FeedItem/LibraryItemCard.swift | 57 +++++++++- .../Sources/Views/Images/Images.swift | 7 ++ .../flair-favorite.imageset/Contents.json | 23 ++++ .../flair-favorite.imageset/Frame-2 1.png | Bin 0 -> 514 bytes .../flair-favorite.imageset/Frame-2 2.png | Bin 0 -> 739 bytes .../flair-favorite.imageset/Frame-2.png | Bin 0 -> 339 bytes .../flair-feed.imageset/Contents.json | 23 ++++ .../flair-feed.imageset/Frame 1.png | Bin 0 -> 491 bytes .../flair-feed.imageset/Frame 2.png | Bin 0 -> 513 bytes .../flair-feed.imageset/Frame.png | Bin 0 -> 397 bytes .../flair-newsletter.imageset/Contents.json | 23 ++++ .../flair-newsletter.imageset/Frame-1 1.png | Bin 0 -> 507 bytes .../flair-newsletter.imageset/Frame-1 2.png | Bin 0 -> 638 bytes .../flair-newsletter.imageset/Frame-1.png | Bin 0 -> 322 bytes .../flair-pinned.imageset/Contents.json | 23 ++++ .../flair-pinned.imageset/Frame-3 1.png | Bin 0 -> 473 bytes .../flair-pinned.imageset/Frame-3 2.png | Bin 0 -> 654 bytes .../flair-pinned.imageset/Frame-3.png | Bin 0 -> 351 bytes .../flair-recommended.imageset/Contents.json | 23 ++++ .../flair-recommended.imageset/Frame-4 1.png | Bin 0 -> 485 bytes .../flair-recommended.imageset/Frame-4 2.png | Bin 0 -> 621 bytes .../flair-recommended.imageset/Frame-4.png | Bin 0 -> 328 bytes 33 files changed, 401 insertions(+), 80 deletions(-) create mode 100644 android/Omnivore/app/src/main/res/drawable/flair_feed.xml create mode 100644 android/Omnivore/app/src/main/res/drawable/flair_newsletter.xml create mode 100644 android/Omnivore/app/src/main/res/drawable/flair_pinned.xml create mode 100644 android/Omnivore/app/src/main/res/drawable/flair_recommended.xml create mode 100644 android/Omnivore/app/src/main/res/drawable/flaire_favorite.xml create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Contents.json create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Frame-2 1.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Frame-2 2.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Frame-2.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-feed.imageset/Contents.json create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-feed.imageset/Frame 1.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-feed.imageset/Frame 2.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-feed.imageset/Frame.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-newsletter.imageset/Contents.json create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-newsletter.imageset/Frame-1 1.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-newsletter.imageset/Frame-1 2.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-newsletter.imageset/Frame-1.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Contents.json create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3 1.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3 2.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Contents.json create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Frame-4 1.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Frame-4 2.png create mode 100644 apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Frame-4.png diff --git a/android/Omnivore/app/build.gradle b/android/Omnivore/app/build.gradle index e525d3c63..1041a5ec9 100644 --- a/android/Omnivore/app/build.gradle +++ b/android/Omnivore/app/build.gradle @@ -17,8 +17,8 @@ android { applicationId "app.omnivore.omnivore" minSdk 26 targetSdk 33 - versionCode 110 - versionName "0.0.110" + versionCode 118 + versionName "0.0.118" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemLabelMutations.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemLabelMutations.kt index e7120536f..e4dd3561f 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemLabelMutations.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemLabelMutations.kt @@ -5,12 +5,12 @@ import app.omnivore.omnivore.graphql.generated.SetLabelsMutation import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput import app.omnivore.omnivore.graphql.generated.type.SetLabelsInput -suspend fun Networker.updateLabelsForSavedItem(input: SetLabelsInput): Boolean { +suspend fun Networker.updateLabelsForSavedItem(input: SetLabelsInput): List? { return try { val result = authenticatedApolloClient().mutation(SetLabelsMutation(input)).execute() - return result.data?.setLabels?.onSetLabelsSuccess?.labels != null + return result.data?.setLabels?.onSetLabelsSuccess?.labels } catch (e: java.lang.Exception) { - false + return null } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelsViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelsViewModel.kt index ddcdaf07b..c9dab6773 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelsViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelsViewModel.kt @@ -56,21 +56,6 @@ class LabelsViewModel @Inject constructor( serverSyncStatus = ServerSyncStatus.NEEDS_CREATION.rawValue ) - viewModelScope.launch { - withContext(Dispatchers.IO) { - dataService.db.savedItemLabelDao().insertAll(listOf(res)) - - val newLabel = networker.createNewLabel(CreateLabelInput(color = presentIfNotNull(res.color), name = res.name)) - if (newLabel != null) { - try { - dataService.db.savedItemLabelDao().updateTempLabel(tempId, newLabel.id) - } catch (e: Exception) { - Log.d("EXCEPTION: ", e.toString()) - } - } - } - } - return res } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt index 632b32950..86dfab019 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt @@ -304,55 +304,44 @@ class LibraryViewModel @Inject constructor( fun updateSavedItemLabels(savedItemID: String, labels: List) { viewModelScope.launch { withContext(Dispatchers.IO) { - val syncedLabels = labels.filter { it.serverSyncStatus == ServerSyncStatus.IS_SYNCED.rawValue } - val unsyncedLabels = labels.filter { it.serverSyncStatus != ServerSyncStatus.IS_SYNCED.rawValue } + val input = SetLabelsInput( + pageId = savedItemID, + labels = Optional.presentIfNotNull(labels.map { CreateLabelInput(color = Optional.presentIfNotNull(it.color), name = it.name) }), + ) - var labelCreationError = false - val createdLabels = unsyncedLabels.mapNotNull { label -> - val result = networker.createNewLabel(CreateLabelInput( - name = label.name, - color = presentIfNotNull(label.color), - description = presentIfNotNull(label.labelDescription), - )) - result?.let { + val updatedLabels = networker.updateLabelsForSavedItem(input) + + // Figure out which of the labels are new + updatedLabels?.let { updatedLabels -> + val existingNamedLabels = dataService.db.savedItemLabelDao() + .namedLabels(updatedLabels.map { it.labelFields.name }) + val existingNames = existingNamedLabels.map { it.name } + val newNamedLabels = updatedLabels.filter { !existingNames.contains(it.labelFields.name) } + + dataService.db.savedItemLabelDao().insertAll(newNamedLabels.map { SavedItemLabel( - savedItemLabelId = result.id, - name = result.name, - color = result.color, - createdAt = result.createdAt.toString(), - labelDescription = result.description, - serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue + savedItemLabelId = it.labelFields.id, + name = it.labelFields.name, + color = it.labelFields.color, + createdAt = null, + labelDescription = null + ) + }) + + val allNamedLabels = dataService.db.savedItemLabelDao() + .namedLabels(updatedLabels.map { it.labelFields.name }) + val crossRefs = allNamedLabels.map { + SavedItemAndSavedItemLabelCrossRef( + savedItemLabelId = it.savedItemLabelId, + savedItemId = savedItemID ) - } ?: run { - labelCreationError = true - null } - } + dataService.db.savedItemAndSavedItemLabelCrossRefDao().deleteRefsBySavedItemId(savedItemID) + dataService.db.savedItemAndSavedItemLabelCrossRefDao().insertAll(crossRefs) - dataService.db.savedItemLabelDao().insertAll(createdLabels) - - val allLabels = syncedLabels + createdLabels - - val input = SetLabelsInput(labelIds = Optional.presentIfNotNull(allLabels.map { it.savedItemLabelId }), pageId = savedItemID) - val networkResult = networker.updateLabelsForSavedItem(input) - - val crossRefs = allLabels.map { - SavedItemAndSavedItemLabelCrossRef( - savedItemLabelId = it.savedItemLabelId, - savedItemId = savedItemID - ) - } - - // Remove all labels first - dataService.db.savedItemAndSavedItemLabelCrossRefDao().deleteRefsBySavedItemId(savedItemID) - - // Add back the current labels - dataService.db.savedItemAndSavedItemLabelCrossRefDao().insertAll(crossRefs) - - if (!networkResult || labelCreationError) { - snackbarMessage = resourceProvider.getString(R.string.library_view_model_snackbar_error) - } else { snackbarMessage = resourceProvider.getString(R.string.library_view_model_snackbar_success) + } ?: run { + snackbarMessage = resourceProvider.getString(R.string.library_view_model_snackbar_error) } CoroutineScope(Dispatchers.Main).launch { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemCard.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemCard.kt index 654fcd22c..be0de7ba5 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemCard.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemCard.kt @@ -20,16 +20,20 @@ import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.toLowerCase +import androidx.compose.ui.text.toUpperCase import androidx.compose.ui.unit.* import app.omnivore.omnivore.R +import app.omnivore.omnivore.persistence.entities.SavedItemLabel import app.omnivore.omnivore.persistence.entities.SavedItemWithLabelsAndHighlights import app.omnivore.omnivore.ui.components.LabelChipColors import app.omnivore.omnivore.ui.library.SavedItemAction +import app.omnivore.omnivore.ui.library.SavedItemFilter import app.omnivore.omnivore.ui.library.SavedItemViewModel import coil.compose.rememberAsyncImagePainter @@ -45,14 +49,14 @@ fun SavedItemCard( Column( modifier = Modifier - .combinedClickable( - onClick = onClickHandler, - onLongClick = { - savedItemViewModel.actionsMenuItemLiveData.postValue(savedItem) - } - ) - .background(if (selected) MaterialTheme.colorScheme.surfaceVariant else MaterialTheme.colorScheme.background) - .fillMaxWidth() + .combinedClickable( + onClick = onClickHandler, + onLongClick = { + savedItemViewModel.actionsMenuItemLiveData.postValue(savedItem) + } + ) + .background(if (selected) MaterialTheme.colorScheme.surfaceVariant else MaterialTheme.colorScheme.background) + .fillMaxWidth() ) { Row( horizontalArrangement = Arrangement.SpaceBetween, @@ -108,8 +112,10 @@ fun SavedItemCard( ) } - FlowRow(modifier = Modifier.fillMaxWidth().padding(10.dp)) { - savedItem.labels.sortedWith(compareBy { it.name.toLowerCase(Locale.current) }).forEach { label -> + FlowRow(modifier = Modifier + .fillMaxWidth() + .padding(10.dp)) { + savedItem.labels.filter { !isFlairLabel(it) }.sortedWith(compareBy { it.name.toLowerCase(Locale.current) }).forEach { label -> val chipColors = LabelChipColors.fromHex(label.color) LabelChip( @@ -196,6 +202,82 @@ fun readingProgress(item: SavedItemWithLabelsAndHighlights): String { // return "" //} + +public enum class FlairIcon( + public val rawValue: String, + public val sortOrder: Int +) { + FEED("feed", 0), + RSS("rss", 0), + FAVORITE("favorite", 1), + NEWSLETTER("newsletter", 2), + RECOMMENDED("recommended", 3), + PINNED("pinned", 4) +} + +val FLAIR_ICON_NAMES = listOf("feed", "rss", "favorite", "newsletter", "recommended", "pinned") + +fun isFlairLabel(label: SavedItemLabel): Boolean { + return FLAIR_ICON_NAMES.contains(label.name.toLowerCase(Locale.current)) +} + +@Composable +fun flairIcons(item: SavedItemWithLabelsAndHighlights) { + val labels = item.labels.filter { isFlairLabel(it) }.map { + FlairIcon.valueOf(it.name.toUpperCase(Locale.current)) + } + labels.forEach { + when (it) { + FlairIcon.RSS, + FlairIcon.FEED -> { + Image( + painter = painterResource(id = R.drawable.flair_feed), + contentDescription = "Feed flair Icon", + modifier = Modifier + .padding(end = 5.0.dp) + ) + } + + FlairIcon.FAVORITE -> { + Image( + painter = painterResource(id = R.drawable.flaire_favorite), + contentDescription = "Favorite flair Icon", + modifier = Modifier + .padding(end = 5.0.dp) + ) + } + + FlairIcon.NEWSLETTER -> { + Image( + painter = painterResource(id = R.drawable.flair_newsletter), + contentDescription = "Newsletter flair Icon", + modifier = Modifier + .padding(end = 5.0.dp) + ) + } + + FlairIcon.RECOMMENDED -> { + Image( + painter = painterResource(id = R.drawable.flair_recommended), + contentDescription = "Recommended flair Icon", + modifier = Modifier + .padding(end = 5.0.dp) + ) + } + + FlairIcon.PINNED -> { + Image( + painter = painterResource(id = R.drawable.flair_pinned), + contentDescription = "Pinned flair Icon", + modifier = Modifier + .padding(end = 5.0.dp) + ) + } + + } + } +} + @Composable fun readInfo(item: SavedItemWithLabelsAndHighlights) { Row( @@ -203,6 +285,9 @@ fun readInfo(item: SavedItemWithLabelsAndHighlights) { .fillMaxWidth() .defaultMinSize(minHeight = 15.dp) ) { + // Show flair here + flairIcons(item) + Text( text = estimatedReadingTime(item), style = TextStyle( diff --git a/android/Omnivore/app/src/main/res/drawable/flair_feed.xml b/android/Omnivore/app/src/main/res/drawable/flair_feed.xml new file mode 100644 index 000000000..aca102b59 --- /dev/null +++ b/android/Omnivore/app/src/main/res/drawable/flair_feed.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/android/Omnivore/app/src/main/res/drawable/flair_newsletter.xml b/android/Omnivore/app/src/main/res/drawable/flair_newsletter.xml new file mode 100644 index 000000000..5c70af531 --- /dev/null +++ b/android/Omnivore/app/src/main/res/drawable/flair_newsletter.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/android/Omnivore/app/src/main/res/drawable/flair_pinned.xml b/android/Omnivore/app/src/main/res/drawable/flair_pinned.xml new file mode 100644 index 000000000..25b42df77 --- /dev/null +++ b/android/Omnivore/app/src/main/res/drawable/flair_pinned.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/android/Omnivore/app/src/main/res/drawable/flair_recommended.xml b/android/Omnivore/app/src/main/res/drawable/flair_recommended.xml new file mode 100644 index 000000000..88a5ea8d3 --- /dev/null +++ b/android/Omnivore/app/src/main/res/drawable/flair_recommended.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/android/Omnivore/app/src/main/res/drawable/flaire_favorite.xml b/android/Omnivore/app/src/main/res/drawable/flaire_favorite.xml new file mode 100644 index 000000000..820704635 --- /dev/null +++ b/android/Omnivore/app/src/main/res/drawable/flaire_favorite.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/apple/Omnivore.xcodeproj/project.pbxproj b/apple/Omnivore.xcodeproj/project.pbxproj index 32ee2a7a5..805222b68 100644 --- a/apple/Omnivore.xcodeproj/project.pbxproj +++ b/apple/Omnivore.xcodeproj/project.pbxproj @@ -1400,7 +1400,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.34.0; + MARKETING_VERSION = 1.35.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; @@ -1435,7 +1435,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; - MARKETING_VERSION = 1.34.0; + MARKETING_VERSION = 1.35.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1490,7 +1490,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.34.0; + MARKETING_VERSION = 1.35.0; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = Omnivore; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1831,7 +1831,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.34.0; + MARKETING_VERSION = 1.35.0; PRODUCT_BUNDLE_IDENTIFIER = app.omnivore.app; PRODUCT_NAME = Omnivore; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift index fff8f9b71..83350cd70 100644 --- a/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift +++ b/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift @@ -2,6 +2,35 @@ import Models import SwiftUI import Utils +enum FlairLabels: String { + case pinned + case favorite + case recommended + case newsletter + case rss + case feed + + var icon: Image { + switch self { + case .pinned: return Image.flairPinned + case .favorite: return Image.flairFavorite + case .recommended: return Image.flairRecommended + case .newsletter: return Image.flairNewsletter + case .feed, .rss: return Image.flairFeed + } + } + + var sortOrder: Int { + switch self { + case .feed, .rss: return 0 + case .favorite: return 1 + case .newsletter: return 2 + case .recommended: return 3 + case .pinned: return 4 + } + } +} + public extension View { func draggableItem(item: LinkedItem) -> some View { #if os(iOS) @@ -124,8 +153,30 @@ public struct LibraryItemCard: View { return "" } + var flairLabels: [FlairLabels] { + item.sortedLabels.compactMap { label in + if let name = label.name { + return FlairLabels(rawValue: name.lowercased()) + } + return nil + }.sorted { $0.sortOrder < $1.sortOrder } + } + + var nonFlairLabels: [LinkedItemLabel] { + item.sortedLabels.filter { label in + if let name = label.name, FlairLabels(rawValue: name.lowercased()) != nil { + return false + } + return true + } + } + var readInfo: some View { - AnyView(HStack { + HStack(alignment: .center, spacing: 5.0) { + ForEach(flairLabels, id: \.self) { + $0.icon + } + let fgcolor = Color.isDarkMode ? Color.themeDarkWhiteGray : Color.themeMiddleGray Text("\(estimatedReadingTime)") .font(.caption2).fontWeight(.medium) @@ -146,7 +197,7 @@ public struct LibraryItemCard: View { .font(.caption2).fontWeight(.medium) .foregroundColor(fgcolor) } - .frame(maxWidth: .infinity, alignment: .leading)) + .frame(maxWidth: .infinity, alignment: .leading) } var imageBox: some View { @@ -227,6 +278,6 @@ public struct LibraryItemCard: View { } var labels: some View { - LabelsFlowLayout(labels: item.sortedLabels) + LabelsFlowLayout(labels: nonFlairLabels) } } diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.swift b/apple/OmnivoreKit/Sources/Views/Images/Images.swift index d32ef814d..ce00165cb 100644 --- a/apple/OmnivoreKit/Sources/Views/Images/Images.swift +++ b/apple/OmnivoreKit/Sources/Views/Images/Images.swift @@ -28,4 +28,11 @@ public extension Image { static var unarchive: Image { Image("unarchive", bundle: .module) } static var remove: Image { Image("remove", bundle: .module) } static var label: Image { Image("label", bundle: .module) } + + static var flairFeed: Image { Image("flair-feed", bundle: .module) } + static var flairFavorite: Image { Image("flair-favorite", bundle: .module) } + + static var flairNewsletter: Image { Image("flair-newsletter", bundle: .module) } + static var flairPinned: Image { Image("flair-pinned", bundle: .module) } + static var flairRecommended: Image { Image("flair-recommended", bundle: .module) } } diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Contents.json b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Contents.json new file mode 100644 index 000000000..6738e3537 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame-2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame-2 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame-2 2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Frame-2 1.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Frame-2 1.png new file mode 100644 index 0000000000000000000000000000000000000000..84b84ba31e2bcf7e22ff199ab545033b2653ff3b GIT binary patch literal 514 zcmV+d0{#7oP)L zHwH@Qb%vF0dwW`;dizMuM6u!uME{TSD&vnp*G35WO@7&R-IO;i4=O2|2au$QTvn z;zWG9%ViM>L8##XsAyb8#*Ng;$z<0)I;EDxx-_w`mWoLP$v3rO^To_nJxCCYDGel13o4 zL=us-0$WL#M79ywiIJ$NU$wGaJo+8SU?Flefiow|H)4ySXp|4ep1j&#<_nwfk8hM*w7sXZP z?|(gpslxc*N@NV*kE_f#sU@-X-%bS441`I+u$TlbFnST03wko27k>u(f;LLfO^~ja zs7NJ=?df?a_TFvD;!O@RyqLE0%LbN89KJn8cgXqX%8~S5 z!{}n{r{V{mnKBWX_kdGC3*5m02x7jIZ?5y6=Ss-EH$%e|=mP;c(?`mh(pHH_okm2M z!XZeX$(>BByJ3|eC9dEg5_DzT4ZB3WtMF(XcEeA`W;`RosRW14f{9Rv>-s-35-G_> zzX!)cU$?K#SVlsUa9VHP3r4izc6>Uq9(r#Ag-xBk*lnG^W}+ws$cVByMqJ zst7QZyB)_CsVczKYuOx0q>cbnyLr~PNL>M@Q3tRuktPC6BMGK$Kgy)30Ml54`P-NJ zf|ep}1ejJ5Ok0t*0!(WOrm0950*pilyxOlfiAV2HtJV@XT?jCpNHBFoxR^Utt7~*b zC+YN*veY_MqXorW6FQe*@nBF9qEzUzof2!Mdah<=f1_lNO@EhVe V8A8u6pN;?k002ovPDHLkV1juFImZA1 literal 0 HcmV?d00001 diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Frame-2.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-favorite.imageset/Frame-2.png new file mode 100644 index 0000000000000000000000000000000000000000..5e93251c38e85f3b74e0078124c4ded44530a95b GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^f*{Pn1|+R>-G2co&H|6fVg?3oVGw3ym^DWND9BhG z%Mf#JQXVcY}`sDwot-1%CEbT&icP6uGy4iSB{*ET{QXZn%~7%POQX zdGS5&T<>ltu6$a}^YfZSBfFIw!(7gYsU5pzseATPHJ^u~fYnvCqUA;(q&$vm?Wo-;U-|WzR#WQh&gn`MIc~hS1JT@@t*wb`o-eQ3(N_@WrE7vG+ z{Oe8G^ixF1VSU7vJ^Mu%Uz%+`W@gSvXvq1MvK48l9zwiJbV)~^d$ zckG)7j>!#Vbnv*HDvTt406~y6A195>;PZVr)lk|XI6PW)hl`9Y+(^Py#ucuV;2TdY zNUyZ6wt5*B+b~5cIHzHV&yNdu9)xtJmEd#{q5Rsnrv(_9Rz?e_OR-MaOb%?@k~iTe z;>xk5v@(8#pvtvyqFfvYYe`+0hBB^jBMDO(SGbjgQU>${;=~2+B%zRTf{&8;CF9|| h?u;?N{B!2?^9|twC(QWd%0&PG002ovPDHLkV1k{0&9wjk literal 0 HcmV?d00001 diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-feed.imageset/Frame 2.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-feed.imageset/Frame 2.png new file mode 100644 index 0000000000000000000000000000000000000000..358758a7e259206b6e4539ce2372d597dd501c9a GIT binary patch literal 513 zcmV+c0{;DpP)W$O$Nli|p0D>S0f-sIkA@say@cA)CrDo7rLaAGI_uZlZ>=I7+#u>LIWY{DE;ayl| zvL%S&U07t2B{IXiWXX^vn8Ujy$wW&O4(~#e2}=BPc$X*{uY|s;Pf_D(1L0ks)uOu? z8&>d9VY&qZE6(-x-r?BLF9H3AZ9u73-G42|#$E}v=pWH_2WImHo4|xOuZcM)Cf?l; ziN3@>>UwTA&rq6Gc!2NfJBCIlr;q7u{k|mQF-X6v`9P~u+et;ws5#A}; zS6@%~C2s0>^L8@$sLhh0hyUv+T^)^GW&;w{%v7X)U2@2djL4p7IL}pKJsU_{bNKs2UFp0r9F@P0XEm4pXD4+>Kc zd?*X;9T}{Pg{s;cn}}f9icVK~#7F?UvtB z!axwlzs=ygC4>^J0IYx##0nVSG%`anqrpcz06NeLqytMZCFEJgtb2xJE^zrv;_#5) zOfttFx!wJCFFBy6r^gH#t#clOF_F? zOGws_{b(i=4!d$+pk3!7B6wKR>+w_`_iT$!A2PCWdH`Ge;1(|wn5MJknDauUvj4{F z0iT94^3dFQC=GsxXSz-UQ0vD^=L8W+Lw-y44o_2?Pp;TiFahcXpt8Tp$Uo;9cKDRJ zk^a|#;c;886&`tn3sJ$94B{+?m3k$qy{|b}+3#e{Xy5b)O{%AWIg-2lbd zsG>@h>z*;7pk9g`}Gn%V1=^+X;v zl3t1Aqhw)LrS@$H5u;Qgxfmx=zZ@OV2a%8sf@*#rItc>O>Hh&^qyIcUPdxBitT*T~ xfF(^)7=$8z5lv*a&4X?r>upR2-JYJa19osN?_u002ovPDHLkV1mOk+5i9m literal 0 HcmV?d00001 diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-newsletter.imageset/Frame-1 2.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-newsletter.imageset/Frame-1 2.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d39f40c17f53d46b88f7c1c91833ececa15514 GIT binary patch literal 638 zcmV-^0)hRBP)vl5z6Q zwBt0PlmFjMSQj7=2m}Iwe~u`e5y>XLaZNLukaSf`OxGMEG0&TnFJd5vG^2ll#qT08 zLjyfTBIbup4CI9FUHHS2t_~NK8aq9bExNbi7b>0G+<-v@g>6l$C8qF$m{!`sSiEwB z#T$DdyL2DY)xv3b!#N@{c4?YWEJATd=_Tkz0=K9R<$e#3VpcRUn@;LTP4i6YH5Og^ ztB2&+bB%KUiWQLT*B!DVesD=CwBRPw$?)!YuOzuY68%j2D0A=S3s#t75nF6V`N0z$`I2cJ8Y?}T;@s!^?XI;OxeY& zviwPO^hd`;LdP5xPJjjXb!>^)V%{s8(c^O8gl!QDJ}Q>o*QvuD(O(%qr98eM_q%X} zOA(3|u-Uv$agk1y6GZqz5aA115p^u#GcsEtbCHPYT=!YXXZiut?VwsmQq}1v@ut*I z!S9KYP(7yHPIToY*>S@SnKyRBvo@yWo5_me4xsA(ozd?Tr)uxl=>La3x`2T|AP{iE YFO<>wJ_@8-G2co&H|6fVg?3oVGw3ym^DWND9BhG zk=-oP z7U9H|df2gaf#E`4D@UIFJav*)JEtCVS5k2dc3Z`|@i@oB&;3l35*xRA8ZMj9!F|hW zl4$;UjtM)I(rPlCxL8}3wjAwS_v)48xf;JO_dJ6?EnU4~)w;r#y_FG*r5s}yc P^df_&tDnm{r-UW|2nKmo literal 0 HcmV?d00001 diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Contents.json b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Contents.json new file mode 100644 index 000000000..a55c67c87 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame-3.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame-3 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame-3 2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3 1.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3 1.png new file mode 100644 index 0000000000000000000000000000000000000000..dba4109e82456de23d833984f77e85ee1aa0a320 GIT binary patch literal 473 zcmV;~0Ve*5P)pmc(cP<4W?kZ#Zo;s?ZQvq2ew1%Q4hH4-AmzOx-E4}21` zF>v?8_Xm{PwCMqrsYI%(YBvnS52hy1^H*a`&wW;_L>kAj#!%pR#{3MZg8OU|2-*b< zFW2*Fnhp|>=x`7KIfUcgjqxnIXswUF&_qGF03;y65F7w5h!}$64Cil{)*Jv12n*sr z!44?FcRE#pS_AP`M_HES{1?YL27p9W13UF{UHbsgc*r@s<~{0R?|Zqp8je{9Oaair zIfbFKU0mIXSqHo;fD-}dpWpXLU$=K`4M1A_fEidkz4}TcTu$YFii@!v$bL z1nNt2vlk*H9JXE%3}FH2F!zP#B>AgyLf8N(+nc5_jvS$m_@RW#Bmnbdv)t38!yenV zy(poqI{{;#E&$S^YJvesPb=$%3t$d{VXq=(g`i({ycvB#jWo$NZAzg(dZPq=_b~S; P00000NkvXXu0mjfGgP>= literal 0 HcmV?d00001 diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3 2.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3 2.png new file mode 100644 index 0000000000000000000000000000000000000000..487a9b2730a3473778309fe8a3ec9b5fcdeb3d00 GIT binary patch literal 654 zcmV;90&)F`P)JT zf#23CJxG8Xx65C=WZG&KqgsRART=Wtab%5OEex97>HwV}@e0?66K~IgvQ^h530X zl~q#}u`VGfP*hhDu__@cP@EO}z;qpqB8eYO+xm=FR4oGM0Q-}TL zOiS(r{%&1$KuSV$#L=a4#w#37w-CU+CP5Hn*ro`jX;nQTi5m%wR;$%eq^@WN`i!{~%GP+DUf7D1OwQqn;ALjj9m(XonJGWERU~Ji?+c+1XR%g@guVh5%C+PLZkr!=VLv`_Tv*0~;!$K$!=7u$}n&5w{9KmY&$07*qoM6N<$f>HPk1ONa4 literal 0 HcmV?d00001 diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-pinned.imageset/Frame-3.png new file mode 100644 index 0000000000000000000000000000000000000000..1d0df2685ef61bdf9ccb7dd654b25cbdbb43f6d3 GIT binary patch literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^f*{Pn1|+R>-G2co&H|6fVg?3oVGw3ym^DWND9BhG zg^*POcuT43k@u{9d*-iyzju904{M3Xr1!r! zzTVZpNMnaq9-pEiPjYnV)vKTP+>BRw@hIT>R*h{MOT|SeF4X2beBsb*>lxabM;`WX z(mB0VC8;hZ`=Ile2QN+~_UtV)$#id0h*#J(+ec2@FX}!lCkF0|}OD=R~B%ET|kz{Bd7rTdh;|ZB8 ul_%0ITP(_d8Xw#)Sl`BT)c@q-Bf{%m$7r(MIldq0e+ExiKbLh*2~7YC;E9C* literal 0 HcmV?d00001 diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Contents.json b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Contents.json new file mode 100644 index 000000000..239db47c1 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Frame-4.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame-4 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame-4 2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Frame-4 1.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Frame-4 1.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ffdd0884641d8567c9dc4197f446432e70d463 GIT binary patch literal 485 zcmVt}>+Y?)PB2GY7@lAZLh(dgzzn=5<uFQ6v``IH+1gk^d}DFz7RUAU_{xpqVtGJc4}H_Pg`E?Uq%GDC(GwX^;P b)EqZoB_(+jD&f8?00000NkvXXu0mjf^wh#t literal 0 HcmV?d00001 diff --git a/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Frame-4 2.png b/apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/flair-recommended.imageset/Frame-4 2.png new file mode 100644 index 0000000000000000000000000000000000000000..3892567f1dbcd8d4f160cd3b00fb89d8d82fdf5c GIT binary patch literal 621 zcmV-z0+RiSP)K-{Wxqb%c!Y-6HOBC3`oCzwycd|79{X@)|U=lVX@k^M= zYg&RxG!=N_E3^3@3&5G3?8K$XoEX0aIKd`?ZmP>~eXPJsBT(XZRAz=h|GL8*rv93-&z8g`dMj{4YX}9xsV$H|s5U|jM{gII7V&3yeI&agKgsp

#wAQg$) zHG3x_LC*M*goJBQTau7)4eF*HDc~5?mJ}rFzDS;c1of^dmR_Q7P+OK>LagAVw@=5O z8cPBb&V1fsv?SgKk;3AsgrFmzj-9uYUDw(l>1s0%4!$kw%_7Q5hpyh(oWr*7n-G2co&H|6fVg?3oVGw3ym^DWND9BhG zKCM6@bWb6T66D!@(xXot&+jwTU(b+DZ9+?nRep&*%SqbaF@{OGFh3* zEIt)qm#4k|{8d{~uzg*ZQrX8+yG17}W1k7f9q`pIU!k*o%a_W%0udfprpO=K%^sL&z?oRQE4ly-gPYR%44}b{(&p|V;Su-BU?-^ zKCu6COkmcmYHyC2HP<)}^|)tu2;6x7`OW(euI$&GIu*?-oNw_r1u-OKr14m-)L+JL W|M0;|Qx>2{89ZJ6T-G@yGywp-JAMlQ literal 0 HcmV?d00001