diff --git a/src/main/java/org/mtransit/android/commons/data/DefaultPOI.java b/src/main/java/org/mtransit/android/commons/data/DefaultPOI.java index 8bdda295..07ae4e1b 100644 --- a/src/main/java/org/mtransit/android/commons/data/DefaultPOI.java +++ b/src/main/java/org/mtransit/android/commons/data/DefaultPOI.java @@ -273,7 +273,7 @@ public static DefaultPOI fromCursorStatic(@NonNull Cursor c, @NonNull String aut authority, getIdFromCursor(c), getDataSourceTypeIdFromCursor(c), - c.getInt(c.getColumnIndexOrThrow(POIProviderContract.Columns.T_POI_K_TYPE)), + getTypeFromCursor(c), c.getInt(c.getColumnIndexOrThrow(POIProviderContract.Columns.T_POI_K_STATUS_TYPE)), CursorExtKt.optIntNN(c, POIProviderContract.Columns.T_POI_K_ACTIONS_TYPE, POI.ITEM_ACTION_TYPE_NONE) ); diff --git a/src/main/java/org/mtransit/android/commons/provider/CaSTOProvider.java b/src/main/java/org/mtransit/android/commons/provider/CaSTOProvider.java index 9313f550..15f33b8b 100644 --- a/src/main/java/org/mtransit/android/commons/provider/CaSTOProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/CaSTOProvider.java @@ -29,6 +29,9 @@ import org.mtransit.android.commons.UriUtils; import org.mtransit.android.commons.data.News; import org.mtransit.android.commons.helpers.MTDefaultHandler; +import org.mtransit.android.commons.provider.config.news.DefaultNewsProviderConfig; +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig; +import org.mtransit.android.commons.provider.config.news.NewsType; import org.mtransit.android.commons.provider.news.NewsTextFormatter; import org.mtransit.commons.SourceUtils; import org.xml.sax.Attributes; @@ -160,6 +163,12 @@ private static String getNEWS_TARGET_AUTHORITY(@NonNull Context context) { return newsTargetAuthority; } + @NonNull + @Override + public NewsProviderConfig getNewsConfig() { + return new DefaultNewsProviderConfig(NewsType.CA_STO); + } + /** * Override if multiple {@link CaSTOProvider} implementations in same app. */ diff --git a/src/main/java/org/mtransit/android/commons/provider/ContentProviderConstants.java b/src/main/java/org/mtransit/android/commons/provider/ContentProviderConstants.java index 663271a2..e4ca5b1b 100644 --- a/src/main/java/org/mtransit/android/commons/provider/ContentProviderConstants.java +++ b/src/main/java/org/mtransit/android/commons/provider/ContentProviderConstants.java @@ -40,5 +40,7 @@ public final class ContentProviderConstants { // public static final int NEWS = 115; // + public static final int CONFIG = 555; + // public static final int ALL = 999; } diff --git a/src/main/java/org/mtransit/android/commons/provider/InstagramNewsProvider.kt b/src/main/java/org/mtransit/android/commons/provider/InstagramNewsProvider.kt index 7c7ad4b2..67fe37d6 100644 --- a/src/main/java/org/mtransit/android/commons/provider/InstagramNewsProvider.kt +++ b/src/main/java/org/mtransit/android/commons/provider/InstagramNewsProvider.kt @@ -24,6 +24,8 @@ import org.mtransit.android.commons.data.News import org.mtransit.android.commons.provider.InstagramNewsProvider.InstagramApi.JEdgeOwnerToTimelineMediaNode import org.mtransit.android.commons.provider.InstagramNewsProvider.InstagramApi.JProfileUser import org.mtransit.android.commons.provider.agency.AgencyUtils +import org.mtransit.android.commons.provider.config.news.instagram.InstagramNewsFeedConfig +import org.mtransit.android.commons.provider.config.news.instagram.InstagramNewsProviderConfig import retrofit2.Call import retrofit2.create import retrofit2.http.GET @@ -140,6 +142,20 @@ class InstagramNewsProvider : NewsProvider() { ) } + override fun getNewsConfig() = InstagramNewsProviderConfig( + newsFeedConfigs = _userNames.mapIndexed { i, username -> + InstagramNewsFeedConfig( + username = username, + lang = _userNamesLang.getOrNull(i) ?: LocaleUtils.UNKNOWN, + color = _userNamesColors.getOrNull(i) ?: _color.takeIf { it.isNotBlank() }, // optional (fallback: agency color) + target = _userNamesTarget.getOrNull(i)?.takeIf { it.isNotBlank() } + ?: _targetAuthority.takeIf { it.isNotBlank() }, // optional (fallback: agency UUID) + severity = _userNamesSeverity.getOrNull(i) ?: InstagramNewsFeedConfig.SEVERITY_DEFAULT, + noteworthy = _userNamesNoteworthy.getOrNull(i) ?: InstagramNewsFeedConfig.NOTEWORTHY_DEFAULT, + ) + } + ) + override fun getLogTag() = LOG_TAG override fun getURI_MATCHER() = _uriMatcher @@ -318,7 +334,7 @@ class InstagramNewsProvider : NewsProvider() { val newNews = ArrayList() val maxValidityInMs = newsMaxValidityInMs val authority = _authority - for ((i, userName) in _userNames.withIndex()) { + _userNames.forEachIndexed { i, userName -> loadUserTimeline( context, getInstagramApi(context), diff --git a/src/main/java/org/mtransit/android/commons/provider/NewsProvider.java b/src/main/java/org/mtransit/android/commons/provider/NewsProvider.java index dfdf96cd..84086d36 100644 --- a/src/main/java/org/mtransit/android/commons/provider/NewsProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/NewsProvider.java @@ -24,6 +24,7 @@ import org.mtransit.android.commons.StringUtils; import org.mtransit.android.commons.TimeUtils; import org.mtransit.android.commons.data.News; +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig; import org.mtransit.commons.CollectionUtils; import org.mtransit.commons.sql.SQLCreateBuilder; import org.mtransit.commons.sql.SQLInsertBuilder; @@ -52,6 +53,7 @@ public static UriMatcher getNewUriMatcher(@NonNull String authority) { public static void append(@NonNull UriMatcher uriMatcher, @NonNull String authority) { uriMatcher.addURI(authority, NewsProviderContract.PING_PATH, ContentProviderConstants.PING); uriMatcher.addURI(authority, NewsProviderContract.NEWS_PATH, ContentProviderConstants.NEWS); + uriMatcher.addURI(authority, NewsProviderContract.CONFIG_PATH, ContentProviderConstants.CONFIG); } @Nullable @@ -142,11 +144,19 @@ public static Cursor queryS(@NonNull NewsProviderContract provider, @NonNull Uri return ContentProviderConstants.EMPTY_CURSOR; // empty cursor = processed case ContentProviderConstants.NEWS: return getNews(provider, selection); + case ContentProviderConstants.CONFIG: + return getNewsConfig(provider); default: return null; // not processed } } + @NonNull + private static Cursor getNewsConfig(@NonNull NewsProviderContract provider) { + final NewsProviderConfig providerNewsConfig = provider.getNewsConfig(); + return providerNewsConfig.toCursor(); + } + @Nullable private static Cursor getNews(@NonNull NewsProviderContract provider, @Nullable String selection) { NewsProviderContract.Filter newsFilter = NewsProviderContract.Filter.fromJSONString(selection); @@ -318,7 +328,9 @@ public String getTypeMT(@NonNull Uri uri) { @Nullable public static String getTypeS(@NonNull NewsProviderContract provider, @NonNull Uri uri) { switch (provider.getURI_MATCHER().match(uri)) { + case ContentProviderConstants.PING: case ContentProviderConstants.NEWS: + case ContentProviderConstants.CONFIG: return StringUtils.EMPTY; // empty string = processed default: return null; // not processed diff --git a/src/main/java/org/mtransit/android/commons/provider/NewsProviderContract.java b/src/main/java/org/mtransit/android/commons/provider/NewsProviderContract.java index 3bd583d2..ff8858fa 100644 --- a/src/main/java/org/mtransit/android/commons/provider/NewsProviderContract.java +++ b/src/main/java/org/mtransit/android/commons/provider/NewsProviderContract.java @@ -19,6 +19,7 @@ import org.mtransit.android.commons.data.News; import org.mtransit.android.commons.data.POI; import org.mtransit.android.commons.data.RouteDirectionStop; +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig; import org.mtransit.commons.CollectionUtils; import java.util.ArrayList; @@ -30,6 +31,7 @@ public interface NewsProviderContract extends ProviderContract { String NEWS_PATH = "news"; + String CONFIG_PATH = "config"; // TODO move to ProviderContract once implemented everywhere boolean REMOVE_IMAGE_FROM_TEXT = false; // TODO later @@ -74,6 +76,9 @@ public interface NewsProviderContract extends ProviderContract { @NonNull Collection getNewsLanguages(); + @NonNull + NewsProviderConfig getNewsConfig(); + interface Columns { String T_NEWS_K_ID = BaseColumns._ID; String T_NEWS_K_AUTHORITY_META = "authority"; @@ -133,6 +138,29 @@ interface Columns { Columns.T_NEWS_K_IMAGE_URL_INDEX + 9, // }; + interface FeedConfigColumns { + String T_NEWS_FEED_CONFIG_K_TYPE = "type"; + String T_NEWS_FEED_CONFIG_K_TARGET = "target"; + String T_NEWS_FEED_CONFIG_K_LANG = "lang"; + String T_NEWS_FEED_CONFIG_K_COLOR = "color"; + String T_NEWS_FEED_CONFIG_K_SEVERITY = "severity"; + String T_NEWS_FEED_CONFIG_K_NOTEWORTHY = "noteworthy"; + + String T_NEWS_FEED_CONFIG_K_EXTRA = "extra"; + + } + + String[] PROJECTION_NEWS_FEED_CONFIG = new String[]{ + FeedConfigColumns.T_NEWS_FEED_CONFIG_K_TYPE, + FeedConfigColumns.T_NEWS_FEED_CONFIG_K_TARGET, + FeedConfigColumns.T_NEWS_FEED_CONFIG_K_LANG, + FeedConfigColumns.T_NEWS_FEED_CONFIG_K_COLOR, + FeedConfigColumns.T_NEWS_FEED_CONFIG_K_SEVERITY, + FeedConfigColumns.T_NEWS_FEED_CONFIG_K_NOTEWORTHY, + + FeedConfigColumns.T_NEWS_FEED_CONFIG_K_EXTRA, + }; + @SuppressWarnings("WeakerAccess") class Filter implements MTLog.Loggable { diff --git a/src/main/java/org/mtransit/android/commons/provider/RSSNewsProvider.java b/src/main/java/org/mtransit/android/commons/provider/RSSNewsProvider.java index 9b434ba9..2eaa6c47 100644 --- a/src/main/java/org/mtransit/android/commons/provider/RSSNewsProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/RSSNewsProvider.java @@ -27,6 +27,7 @@ import org.mtransit.android.commons.UriUtils; import org.mtransit.android.commons.data.News; import org.mtransit.android.commons.helpers.MTDefaultHandler; +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig; import org.mtransit.android.commons.provider.news.NewsTextFormatter; import org.mtransit.android.commons.provider.news.rss.RssNewProviderUtils; import org.mtransit.commons.CleanUtils; @@ -234,6 +235,12 @@ private static java.util.List getFEEDS_LABEL(@NonNull Context context) { return feedsLabel; } + @NonNull + @Override + public NewsProviderConfig getNewsConfig() { + return RssNewProviderUtils.getNewsConfig(requireContextCompat()); + } + @NonNull @Override public UriMatcher getURI_MATCHER() { diff --git a/src/main/java/org/mtransit/android/commons/provider/TwitterNewsProvider.kt b/src/main/java/org/mtransit/android/commons/provider/TwitterNewsProvider.kt index 5777c310..13cee460 100644 --- a/src/main/java/org/mtransit/android/commons/provider/TwitterNewsProvider.kt +++ b/src/main/java/org/mtransit/android/commons/provider/TwitterNewsProvider.kt @@ -24,6 +24,8 @@ import org.mtransit.android.commons.TimeUtils import org.mtransit.android.commons.UriUtils import org.mtransit.android.commons.data.News import org.mtransit.android.commons.provider.agency.AgencyUtils +import org.mtransit.android.commons.provider.config.news.twitter.TwitterNewsFeedConfig +import org.mtransit.android.commons.provider.config.news.twitter.TwitterNewsProviderConfig import org.mtransit.android.commons.provider.news.NewsTextFormatter import org.mtransit.android.commons.provider.news.twitter.model.Tweet import org.mtransit.android.commons.provider.news.twitter.model.TweetMediaType @@ -221,6 +223,21 @@ class TwitterNewsProvider : NewsProvider() { ) } + override fun getNewsConfig() = TwitterNewsProviderConfig( + newsFeedConfigs = _userNames.mapIndexed { i, username -> + TwitterNewsFeedConfig( + username = username, + userId = _userNamesId.getOrNull(i), // optional (saved 1 request) + lang = _userNamesLang.getOrNull(i) ?: LocaleUtils.UNKNOWN, + color = _userNamesColors.getOrNull(i) ?: _color.takeIf { it.isNotBlank() }, // optional (fallback: agency color) + target = _userNamesTarget.getOrNull(i)?.takeIf { it.isNotBlank() } + ?: _targetAuthority.takeIf { it.isNotBlank() }, // optional (fallback: agency UUID) + severity = _userNamesSeverity.getOrNull(i) ?: TwitterNewsFeedConfig.SEVERITY_DEFAULT, + noteworthy = _userNamesNoteworthy.getOrNull(i) ?: TwitterNewsFeedConfig.NOTEWORTHY_DEFAULT, + ) + } + ) + override fun getLogTag() = LOG_TAG override fun getURI_MATCHER() = _uriMatcher @@ -414,7 +431,7 @@ class TwitterNewsProvider : NewsProvider() { val newNews = ArrayList() val maxValidityInMs = newsMaxValidityInMs val authority = _authority - for ((i, userName) in _userNames.withIndex()) { + _userNames.forEachIndexed { i, userName -> loadUserTimeline( context, twitterApi, @@ -527,10 +544,16 @@ class TwitterNewsProvider : NewsProvider() { val tweetsResp = response.data val tweetsRespIncludedExpansions = response.includes var newSinceId: String? = null + val colorString = _userNamesColors.getOrNull(i)?.takeIf { it.isNotBlank() } + ?: _color.takeIf { it.isNotBlank() } + ?: AgencyUtils.getAgencyColor(context) + ?: ColorUtils.BLACK + .also { + MTLog.w(this, "No color found for '$username'! (used fallback)") + } tweetsResp ?.forEach { tweet -> readNews( - context, tweet, tweetsRespIncludedExpansions, authority, @@ -541,7 +564,8 @@ class TwitterNewsProvider : NewsProvider() { targetUUID, userId, username, - userLang + userLang, + colorString, )?.apply { if (newSinceId == null) { newSinceId = tweet.id @@ -571,7 +595,6 @@ class TwitterNewsProvider : NewsProvider() { @RequiresApi(Build.VERSION_CODES.O) private fun readNews( - context: Context, tweet: Tweet, includedExpansions: TweetIncludes?, authority: String, @@ -583,6 +606,7 @@ class TwitterNewsProvider : NewsProvider() { userId: String, userName: String, userLang: String, + colorString: String, ): News? { if (tweet.inReplyToUserId != null && tweet.inReplyToUserId != userId) { MTLog.d(this, "readNews() > SKIP (in reply to screen name: '%s').", tweet.inReplyToUserId) @@ -615,13 +639,6 @@ class TwitterNewsProvider : NewsProvider() { val lang: String = getLang(tweet, userLang) val createdAtInMs = tweet.createdAt?.time ?: newLastUpdateInMs // should never happen - val colorString = _userNamesColors.getOrNull(_userNames.indexOf(authorUserName))?.takeIf { it.isNotBlank() } - ?: _color.takeIf { it.isNotBlank() } - ?: AgencyUtils.getAgencyColor(context) - ?: ColorUtils.BLACK - .also { - MTLog.w(this, "No color found for '$userName'! (used fallback)") - } return News( null, authority, diff --git a/src/main/java/org/mtransit/android/commons/provider/WinnipegTransitProvider.java b/src/main/java/org/mtransit/android/commons/provider/WinnipegTransitProvider.java index dc810ee5..68b98cce 100644 --- a/src/main/java/org/mtransit/android/commons/provider/WinnipegTransitProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/WinnipegTransitProvider.java @@ -39,6 +39,9 @@ import org.mtransit.android.commons.data.POIStatus; import org.mtransit.android.commons.data.RouteDirectionStop; import org.mtransit.android.commons.data.Schedule; +import org.mtransit.android.commons.provider.config.news.DefaultNewsProviderConfig; +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig; +import org.mtransit.android.commons.provider.config.news.NewsType; import org.mtransit.commons.CleanUtils; import org.mtransit.commons.SourceUtils; import org.mtransit.commons.provider.WinnipegTransitProviderCommons; @@ -180,6 +183,12 @@ private static String getNEWS_TARGET_AUTHORITY(@NonNull Context context) { return newsTargetAuthority; } + @NonNull + @Override + public NewsProviderConfig getNewsConfig() { + return new DefaultNewsProviderConfig(NewsType.CA_WINNIPEG); + } + private static final long WEB_SERVICE_STATUS_MAX_VALIDITY_IN_MS = TimeUnit.HOURS.toMillis(1L); private static final long WEB_SERVICE_STATUS_VALIDITY_IN_MS = TimeUnit.MINUTES.toMillis(10L); private static final long WEB_SERVICE_STATUS_VALIDITY_IN_FOCUS_IN_MS = TimeUnit.MINUTES.toMillis(1L); diff --git a/src/main/java/org/mtransit/android/commons/provider/YouTubeNewsProvider.kt b/src/main/java/org/mtransit/android/commons/provider/YouTubeNewsProvider.kt index 53a5de03..1d16532b 100644 --- a/src/main/java/org/mtransit/android/commons/provider/YouTubeNewsProvider.kt +++ b/src/main/java/org/mtransit/android/commons/provider/YouTubeNewsProvider.kt @@ -20,6 +20,8 @@ import org.mtransit.android.commons.UriUtils import org.mtransit.android.commons.data.News import org.mtransit.android.commons.linkifyAllURLs import org.mtransit.android.commons.provider.agency.AgencyUtils +import org.mtransit.android.commons.provider.config.news.youtube.YouTubeNewsFeedConfig +import org.mtransit.android.commons.provider.config.news.youtube.YouTubeNewsProviderConfig import org.mtransit.android.commons.provider.news.NewsTextFormatter import org.mtransit.android.commons.provider.news.youtube.YouTubeDateAdapter import org.mtransit.android.commons.provider.news.youtube.YouTubeV3Api @@ -179,6 +181,22 @@ class YouTubeNewsProvider : NewsProvider() { ) } + override fun getNewsConfig() = YouTubeNewsProviderConfig( + newsFeedConfigs = _authorUrls.mapIndexed { i, authorUrl -> + YouTubeNewsFeedConfig( + authorUrl = authorUrl, + username = _userNames.getOrNull(i), + userHandle = _userNamesHandles.getOrNull(i), + channelId = _userNamesChannelsId.getOrNull(i), + lang = _userNamesLang.getOrNull(i) ?: LocaleUtils.UNKNOWN, + color = _userNamesColors.getOrNull(i), + target = _userNamesTarget.getOrNull(i), + severity = _userNamesSeverity.getOrNull(i) ?: YouTubeNewsFeedConfig.SEVERITY_DEFAULT, + noteworthy = _userNamesNoteworthy.getOrNull(i) ?: YouTubeNewsFeedConfig.NOTEWORTHY_DEFAULT, + ) + } + ) + override fun getLogTag() = LOG_TAG override fun getURI_MATCHER() = _uriMatcher @@ -353,7 +371,7 @@ class YouTubeNewsProvider : NewsProvider() { val newNews = ArrayList() val maxValidityInMs = newsMaxValidityInMs val authority = _authority - for ((i, authorUrl) in _authorUrls.withIndex()) { + _authorUrls.forEachIndexed { i, authorUrl -> loadUserUploadsPlaylist( context, youTubeApi, diff --git a/src/main/java/org/mtransit/android/commons/provider/config/ProviderConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/ProviderConfig.kt new file mode 100644 index 00000000..88942dbd --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/ProviderConfig.kt @@ -0,0 +1,3 @@ +package org.mtransit.android.commons.provider.config + +interface ProviderConfig diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/DefaultNewsProviderConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/DefaultNewsProviderConfig.kt new file mode 100644 index 00000000..1bece66e --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/DefaultNewsProviderConfig.kt @@ -0,0 +1,16 @@ +package org.mtransit.android.commons.provider.config.news + +import android.database.Cursor + +data class DefaultNewsProviderConfig @JvmOverloads constructor( + override val type: NewsType, + override val newsFeedConfigs: List = emptyList() +) : NewsProviderConfig { + companion object { + fun getTypeFromCursor(cursor: Cursor): NewsType? = NewsType.fromId( + NewsFeedConfig.getTypeIdFromCursorRow(cursor) + ) + + fun fromCursor(newsType: NewsType): NewsProviderConfig = DefaultNewsProviderConfig(newsType,) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/NewsFeedConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/NewsFeedConfig.kt new file mode 100644 index 00000000..df46d174 --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/NewsFeedConfig.kt @@ -0,0 +1,50 @@ +package org.mtransit.android.commons.provider.config.news + +import android.database.Cursor +import androidx.core.database.getStringOrNull +import org.mtransit.android.commons.LocaleUtils +import org.mtransit.android.commons.provider.NewsProviderContract.FeedConfigColumns + +interface NewsFeedConfig { + val target: String? get() = null // target the entire agency + val lang: String get() = LocaleUtils.UNKNOWN // show all + val color: String? get() = null // same as agency (target?) color + val severity: Int get() = 1 // news_provider_severity_info_unknown + val noteworthy: Long get() = 86_400_000L // news_provider_noteworthy_info // 1 days + + /** + * See [FeedConfigColumns] + * See [org.mtransit.android.commons.provider.NewsProviderContract.PROJECTION_NEWS_FEED_CONFIG] + */ + fun toCursorRow(): Array + + fun makeCursorRow(type: NewsType, extra: String? = null) = arrayOf( + type.id, + target.orEmpty(), + lang, + color.orEmpty(), + severity, + noteworthy, + extra.orEmpty(), + ) + + fun fromCursorRow(row: Array): NewsFeedConfig + + companion object { + fun getTypeIdFromCursorRow(row: Array): Int = row[0] as Int + fun getTargetFromCursorRow(row: Array): String? = (row.getOrNull(1) as? String)?.takeIf { it.isNotEmpty() } + fun getLangFromCursorRow(row: Array): String = row[2] as String + fun getColorFromCursorRow(row: Array): String? = (row.getOrNull(3) as? String)?.takeIf { it.isNotEmpty() } + fun getSeverityFromCursorRow(row: Array): Int = row[4] as Int + fun getNoteworthyFromCursorRow(row: Array): Long = row[5] as Long + fun getExtraFromCursorRow(row: Array): String? = (row.getOrNull(6) as? String)?.takeIf { it.isNotEmpty() } + + fun getTypeIdFromCursorRow(cursor: Cursor): Int = cursor.getInt(cursor.getColumnIndexOrThrow(FeedConfigColumns.T_NEWS_FEED_CONFIG_K_TYPE)) + fun getTargetFromCursorRow(cursor: Cursor): String? = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(FeedConfigColumns.T_NEWS_FEED_CONFIG_K_TARGET)) + fun getLangFromCursorRow(cursor: Cursor): String = cursor.getString(cursor.getColumnIndexOrThrow(FeedConfigColumns.T_NEWS_FEED_CONFIG_K_LANG)) + fun getColorFromCursorRow(cursor: Cursor): String? = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(FeedConfigColumns.T_NEWS_FEED_CONFIG_K_COLOR)) + fun getSeverityFromCursorRow(cursor: Cursor): Int = cursor.getInt(cursor.getColumnIndexOrThrow(FeedConfigColumns.T_NEWS_FEED_CONFIG_K_SEVERITY)) + fun getNoteworthyFromCursorRow(cursor: Cursor): Long = cursor.getLong(cursor.getColumnIndexOrThrow(FeedConfigColumns.T_NEWS_FEED_CONFIG_K_NOTEWORTHY)) + fun getExtraFromCursorRow(cursor: Cursor): String? = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(FeedConfigColumns.T_NEWS_FEED_CONFIG_K_EXTRA)) + } +} \ No newline at end of file diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/NewsProviderConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/NewsProviderConfig.kt new file mode 100644 index 00000000..fb4c946a --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/NewsProviderConfig.kt @@ -0,0 +1,39 @@ +package org.mtransit.android.commons.provider.config.news + +import android.database.Cursor +import android.database.MatrixCursor +import org.mtransit.android.commons.provider.NewsProviderContract +import org.mtransit.android.commons.provider.config.ProviderConfig +import org.mtransit.android.commons.provider.config.news.instagram.InstagramNewsProviderConfig +import org.mtransit.android.commons.provider.config.news.rss.RSSNewsProviderConfig +import org.mtransit.android.commons.provider.config.news.twitter.TwitterNewsProviderConfig +import org.mtransit.android.commons.provider.config.news.youtube.YouTubeNewsProviderConfig + +interface NewsProviderConfig : ProviderConfig { + val type: NewsType + val newsFeedConfigs: List + + fun toCursor(): Cursor = + MatrixCursor(NewsProviderContract.PROJECTION_NEWS_FEED_CONFIG).apply { + newsFeedConfigs.forEach { newsFeedConfig -> + addRow(newsFeedConfig.toCursorRow()) + } + } + + companion object { + + @JvmStatic + fun fromCursor(cursor: Cursor?): NewsProviderConfig? { + cursor ?: return null + val newsType = DefaultNewsProviderConfig.getTypeFromCursor(cursor) ?: return null + return when (newsType) { + NewsType.RSS -> RSSNewsProviderConfig.fromCursor(cursor) + NewsType.YOUTUBE -> YouTubeNewsProviderConfig.fromCursor(cursor) + NewsType.TWITTER -> TwitterNewsProviderConfig.fromCursor(cursor) + NewsType.INSTAGRAM -> InstagramNewsProviderConfig.fromCursor(cursor) + NewsType.CA_STO -> DefaultNewsProviderConfig.fromCursor(newsType) + NewsType.CA_WINNIPEG -> DefaultNewsProviderConfig.fromCursor(newsType) + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/NewsType.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/NewsType.kt new file mode 100644 index 00000000..38fc422e --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/NewsType.kt @@ -0,0 +1,18 @@ +package org.mtransit.android.commons.provider.config.news + +enum class NewsType(val id: Int) { + + RSS(0), + YOUTUBE(1), + TWITTER(2), + INSTAGRAM(3), + + CA_STO(100), + CA_WINNIPEG(101), + + ; + + companion object { + fun fromId(id: Int) = entries.singleOrNull { it.id == id } + } +} \ No newline at end of file diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/instagram/InstagramNewsFeedConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/instagram/InstagramNewsFeedConfig.kt new file mode 100644 index 00000000..9304fd00 --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/instagram/InstagramNewsFeedConfig.kt @@ -0,0 +1,70 @@ +package org.mtransit.android.commons.provider.config.news.instagram + +import android.database.Cursor +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.put +import org.mtransit.android.commons.LocaleUtils +import org.mtransit.android.commons.provider.config.news.NewsFeedConfig +import org.mtransit.android.commons.provider.config.news.NewsType +import java.lang.IllegalStateException + +data class InstagramNewsFeedConfig( + val username: String, + override val target: String? = null, + override val lang: String = LocaleUtils.UNKNOWN, // show all + override val color: String? = null, + override val severity: Int = SEVERITY_DEFAULT, + override val noteworthy: Long = NOTEWORTHY_DEFAULT, +) : NewsFeedConfig { + + companion object { + const val SEVERITY_DEFAULT = 2 // news_provider_severity_info_agency + const val NOTEWORTHY_DEFAULT = 604_800_000L // news_provider_noteworthy_long_term // 1 week + + fun fromCursor(cursor: Cursor) = buildList { + while (cursor.moveToNext()) { + add(fromCursorRow(cursor)) + } + } + + private fun fromCursorRow(cursor: Cursor): InstagramNewsFeedConfig { + val extraFromCursorRow = NewsFeedConfig.getExtraFromCursorRow(cursor) ?: throw IllegalStateException("Extra is missing") + val extra = Json.parseToJsonElement(extraFromCursorRow).jsonObject + return InstagramNewsFeedConfig( + username = extra["username"]?.jsonPrimitive?.content ?: throw IllegalArgumentException("Missing username"), + target = NewsFeedConfig.getTargetFromCursorRow(cursor), + lang = NewsFeedConfig.getLangFromCursorRow(cursor), + color = NewsFeedConfig.getColorFromCursorRow(cursor), + severity = NewsFeedConfig.getSeverityFromCursorRow(cursor), + noteworthy = NewsFeedConfig.getNoteworthyFromCursorRow(cursor), + ) + } + } + + override fun toCursorRow(): Array { + return makeCursorRow( + type = NewsType.INSTAGRAM, + extra = Json.encodeToString( + buildJsonObject { + put("username", username) + } + ) + ) + } + + override fun fromCursorRow(row: Array): NewsFeedConfig { + val extraFromCursorRow = NewsFeedConfig.getExtraFromCursorRow(row) ?: throw IllegalStateException("Extra is missing") + val extra = Json.parseToJsonElement(extraFromCursorRow).jsonObject + return InstagramNewsFeedConfig( + username = extra["username"]?.jsonPrimitive?.content ?: throw IllegalArgumentException("Missing username"), + target = NewsFeedConfig.getTargetFromCursorRow(row), + lang = NewsFeedConfig.getLangFromCursorRow(row), + color = NewsFeedConfig.getColorFromCursorRow(row), + severity = NewsFeedConfig.getSeverityFromCursorRow(row), + noteworthy = NewsFeedConfig.getNoteworthyFromCursorRow(row), + ) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/instagram/InstagramNewsProviderConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/instagram/InstagramNewsProviderConfig.kt new file mode 100644 index 00000000..41b0a669 --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/instagram/InstagramNewsProviderConfig.kt @@ -0,0 +1,17 @@ +package org.mtransit.android.commons.provider.config.news.instagram + +import android.database.Cursor +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig +import org.mtransit.android.commons.provider.config.news.NewsType + +data class InstagramNewsProviderConfig( + override val newsFeedConfigs: List +) : NewsProviderConfig { + override val type = NewsType.INSTAGRAM + + companion object { + fun fromCursor(cursor: Cursor)= InstagramNewsProviderConfig( + newsFeedConfigs = InstagramNewsFeedConfig.fromCursor(cursor) + ) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/rss/RSSNewsFeedConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/rss/RSSNewsFeedConfig.kt new file mode 100644 index 00000000..f2cd170a --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/rss/RSSNewsFeedConfig.kt @@ -0,0 +1,110 @@ +package org.mtransit.android.commons.provider.config.news.rss + +import android.database.Cursor +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.booleanOrNull +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.put +import org.mtransit.android.commons.LocaleUtils +import org.mtransit.android.commons.provider.config.news.NewsFeedConfig +import org.mtransit.android.commons.provider.config.news.NewsType +import java.lang.IllegalStateException + +data class RSSNewsFeedConfig( + val url: String, // rss feed url + val label: String? = null, // should be guessed from url + val authorIcon: String? = null, + val authorName: String? = null, // fallback to agency short name + val authorUrl: String, + val encoding: String = ENCODING_DEFAULT, + val copyToFile: Boolean = COPY_FILE_DEFAULT, // instead of streaming + val ignoreGUID: Boolean = IGNORE_GUID_DEFAULT, + val ignoreLink: Boolean = IGNORE_LINK_DEFAULT, + override val target: String? = null, + override val lang: String = LocaleUtils.UNKNOWN, // show all + override val color: String? = null, + override val severity: Int = SEVERITY_DEFAULT, + override val noteworthy: Long = NOTEWORTHY_DEFAULT, +) : NewsFeedConfig { + + companion object { + const val SEVERITY_DEFAULT = 2 // news_provider_severity_info_agency + const val NOTEWORTHY_DEFAULT = 10_800_000L // news_provider_noteworthy_warning // 3 hours + + const val ENCODING_DEFAULT = "UTF-8" + const val COPY_FILE_DEFAULT = false + const val IGNORE_GUID_DEFAULT = false + const val IGNORE_LINK_DEFAULT = false + + fun fromCursor(cursor: Cursor) = buildList { + while (cursor.moveToNext()) { + add(fromCursorRow(cursor)) + } + } + + private fun fromCursorRow(cursor: Cursor): RSSNewsFeedConfig { + val extraFromCursorRow = NewsFeedConfig.getExtraFromCursorRow(cursor) ?: throw IllegalStateException("Extra is missing") + val extra = Json.parseToJsonElement(extraFromCursorRow).jsonObject + return RSSNewsFeedConfig( + url = extra["url"]?.jsonPrimitive?.content ?: throw IllegalStateException("URL is missing"), + label = extra["label"]?.jsonPrimitive?.contentOrNull, + authorIcon = extra["authorIcon"]?.jsonPrimitive?.contentOrNull, + authorName = extra["authorName"]?.jsonPrimitive?.contentOrNull, + authorUrl = extra["authorUrl"]?.jsonPrimitive?.content ?: throw IllegalStateException("Author URL is missing"), + encoding = extra["encoding"]?.jsonPrimitive?.contentOrNull ?: ENCODING_DEFAULT, + copyToFile = extra["copyToFile"]?.jsonPrimitive?.booleanOrNull ?: COPY_FILE_DEFAULT, + ignoreGUID = extra["ignoreGUID"]?.jsonPrimitive?.booleanOrNull ?: IGNORE_GUID_DEFAULT, + ignoreLink = extra["ignoreLink"]?.jsonPrimitive?.booleanOrNull ?: IGNORE_LINK_DEFAULT, + target = NewsFeedConfig.getTargetFromCursorRow(cursor), + lang = NewsFeedConfig.getLangFromCursorRow(cursor), + color = NewsFeedConfig.getColorFromCursorRow(cursor), + severity = NewsFeedConfig.getSeverityFromCursorRow(cursor), + noteworthy = NewsFeedConfig.getNoteworthyFromCursorRow(cursor), + ) + } + } + + @Suppress("SimplifyBooleanWithConstants") + override fun toCursorRow(): Array { + return makeCursorRow( + type = NewsType.RSS, + extra = Json.encodeToString( + buildJsonObject { + put("url", url) + label?.let { put("label", it) } + authorIcon?.let { put("authorIcon", it) } + authorName?.let { put("authorName", it) } + put("authorUrl", authorUrl) + put("encoding", encoding) + if (copyToFile != COPY_FILE_DEFAULT) put("copyToFile", copyToFile) + if (ignoreGUID != IGNORE_GUID_DEFAULT) put("ignoreGUID", ignoreGUID) + if (ignoreLink != IGNORE_LINK_DEFAULT) put("ignoreLink", ignoreLink) + } + ) + ) + } + + override fun fromCursorRow(row: Array): NewsFeedConfig { + val extraFromCursorRow = NewsFeedConfig.getExtraFromCursorRow(row) ?: throw IllegalStateException("Extra is missing") + val extra = Json.parseToJsonElement(extraFromCursorRow).jsonObject + return RSSNewsFeedConfig( + url = extra["url"]?.jsonPrimitive?.content ?: throw IllegalStateException("URL is missing"), + label = extra["label"]?.jsonPrimitive?.contentOrNull, + authorIcon = extra["authorIcon"]?.jsonPrimitive?.contentOrNull, + authorName = extra["authorName"]?.jsonPrimitive?.contentOrNull, + authorUrl = extra["authorUrl"]?.jsonPrimitive?.content ?: throw IllegalStateException("Author URL is missing"), + encoding = extra["encoding"]?.jsonPrimitive?.contentOrNull ?: ENCODING_DEFAULT, + copyToFile = extra["copyToFile"]?.jsonPrimitive?.booleanOrNull ?: COPY_FILE_DEFAULT, + ignoreGUID = extra["ignoreGUID"]?.jsonPrimitive?.booleanOrNull ?: IGNORE_GUID_DEFAULT, + ignoreLink = extra["ignoreLink"]?.jsonPrimitive?.booleanOrNull ?: IGNORE_LINK_DEFAULT, + target = NewsFeedConfig.getTargetFromCursorRow(row), + lang = NewsFeedConfig.getLangFromCursorRow(row), + color = NewsFeedConfig.getColorFromCursorRow(row), + severity = NewsFeedConfig.getSeverityFromCursorRow(row), + noteworthy = NewsFeedConfig.getNoteworthyFromCursorRow(row), + ) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/rss/RSSNewsProviderConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/rss/RSSNewsProviderConfig.kt new file mode 100644 index 00000000..d01ab47f --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/rss/RSSNewsProviderConfig.kt @@ -0,0 +1,17 @@ +package org.mtransit.android.commons.provider.config.news.rss + +import android.database.Cursor +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig +import org.mtransit.android.commons.provider.config.news.NewsType + +data class RSSNewsProviderConfig( + override val newsFeedConfigs: List +) : NewsProviderConfig { + override val type = NewsType.RSS + + companion object { + fun fromCursor(cursor: Cursor) = RSSNewsProviderConfig( + newsFeedConfigs = RSSNewsFeedConfig.fromCursor(cursor) + ) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/twitter/TwitterNewsFeedConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/twitter/TwitterNewsFeedConfig.kt new file mode 100644 index 00000000..75a13497 --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/twitter/TwitterNewsFeedConfig.kt @@ -0,0 +1,75 @@ +package org.mtransit.android.commons.provider.config.news.twitter + +import android.database.Cursor +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.put +import org.mtransit.android.commons.LocaleUtils +import org.mtransit.android.commons.provider.config.news.NewsFeedConfig +import org.mtransit.android.commons.provider.config.news.NewsType +import java.lang.IllegalStateException + +data class TwitterNewsFeedConfig( + val username: String, + val userId: String? = null, // optional (saved 1 call to Twitter API) + override val target: String? = null, + override val lang: String = LocaleUtils.UNKNOWN, // TODO ? LocaleUtils.MULTIPLE, // detect lang from Twitter API + override val color: String? = null, + override val severity: Int = SEVERITY_DEFAULT, + override val noteworthy: Long = NOTEWORTHY_DEFAULT, +) : NewsFeedConfig { + + companion object { + const val SEVERITY_DEFAULT = 2 // news_provider_severity_info_agency + const val NOTEWORTHY_DEFAULT = 10_800_000L // news_provider_noteworthy_warning // 3 hours + + fun fromCursor(cursor: Cursor) = buildList { + while (cursor.moveToNext()) { + add(fromCursorRow(cursor)) + } + } + + private fun fromCursorRow(cursor: Cursor): TwitterNewsFeedConfig { + val extraFromCursorRow = NewsFeedConfig.getExtraFromCursorRow(cursor) ?: throw IllegalStateException("Extra is missing") + val extra = Json.parseToJsonElement(extraFromCursorRow).jsonObject + return TwitterNewsFeedConfig( + username = extra["username"]?.jsonPrimitive?.content ?: throw IllegalStateException("username is missing"), + userId = extra["userId"]?.jsonPrimitive?.contentOrNull, + target = NewsFeedConfig.getTargetFromCursorRow(cursor), + lang = NewsFeedConfig.getLangFromCursorRow(cursor), + color = NewsFeedConfig.getColorFromCursorRow(cursor), + severity = NewsFeedConfig.getSeverityFromCursorRow(cursor), + noteworthy = NewsFeedConfig.getNoteworthyFromCursorRow(cursor), + ) + } + } + + override fun toCursorRow(): Array { + return makeCursorRow( + type = NewsType.TWITTER, + extra = Json.encodeToString( + buildJsonObject { + put("username", username) + userId?.let { put("userId", it) } + } + ) + ) + } + + override fun fromCursorRow(row: Array): NewsFeedConfig { + val extraFromCursorRow = NewsFeedConfig.getExtraFromCursorRow(row) ?: throw IllegalStateException("Extra is missing") + val extra = Json.parseToJsonElement(extraFromCursorRow).jsonObject + return TwitterNewsFeedConfig( + username = extra["username"]?.jsonPrimitive?.content ?: throw IllegalStateException("username is missing"), + userId = extra["userId"]?.jsonPrimitive?.contentOrNull, + target = NewsFeedConfig.getTargetFromCursorRow(row), + lang = NewsFeedConfig.getLangFromCursorRow(row), + color = NewsFeedConfig.getColorFromCursorRow(row), + severity = NewsFeedConfig.getSeverityFromCursorRow(row), + noteworthy = NewsFeedConfig.getNoteworthyFromCursorRow(row), + ) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/twitter/TwitterNewsProviderConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/twitter/TwitterNewsProviderConfig.kt new file mode 100644 index 00000000..b08db669 --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/twitter/TwitterNewsProviderConfig.kt @@ -0,0 +1,17 @@ +package org.mtransit.android.commons.provider.config.news.twitter + +import android.database.Cursor +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig +import org.mtransit.android.commons.provider.config.news.NewsType + +data class TwitterNewsProviderConfig( + override val newsFeedConfigs: List +) : NewsProviderConfig { + override val type = NewsType.TWITTER + + companion object { + fun fromCursor(cursor: Cursor)= TwitterNewsProviderConfig( + newsFeedConfigs = TwitterNewsFeedConfig.fromCursor(cursor) + ) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/youtube/YouTubeNewsFeedConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/youtube/YouTubeNewsFeedConfig.kt new file mode 100644 index 00000000..3d4ff3ef --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/youtube/YouTubeNewsFeedConfig.kt @@ -0,0 +1,83 @@ +package org.mtransit.android.commons.provider.config.news.youtube + +import android.database.Cursor +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.put +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import org.mtransit.android.commons.LocaleUtils +import org.mtransit.android.commons.provider.config.news.NewsFeedConfig +import org.mtransit.android.commons.provider.config.news.NewsType +import java.lang.IllegalStateException + +data class YouTubeNewsFeedConfig( + val authorUrl: String, // can extract "username OR @userHandle or channel ID" from url + val username: String? = null, // optional (username OR @userHandle or channel ID) + val userHandle: String? = null, // optional (username OR @userHandle or channel ID) + val channelId: String? = null, // optional (username OR @userHandle or channel ID) + override val target: String? = null, // default to agency + override val color: String? = null, // defaults to agency + override val lang: String = LocaleUtils.UNKNOWN, // show all + override val severity: Int = SEVERITY_DEFAULT, + override val noteworthy: Long = NOTEWORTHY_DEFAULT, +) : NewsFeedConfig { + + companion object { + const val SEVERITY_DEFAULT = 2 // news_provider_severity_info_agency + const val NOTEWORTHY_DEFAULT = 604_800_000L // news_provider_noteworthy_long_term // 1 week + + fun fromCursor(cursor: Cursor) = buildList { + while (cursor.moveToNext()) { + add(fromCursorRow(cursor)) + } + } + + private fun fromCursorRow(cursor: Cursor): YouTubeNewsFeedConfig { + val extraFromCursorRow = NewsFeedConfig.getExtraFromCursorRow(cursor) ?: throw IllegalStateException("Extra is missing") + val extra = Json.parseToJsonElement(extraFromCursorRow).jsonObject + return YouTubeNewsFeedConfig( + authorUrl = extra["authorUrl"]?.jsonPrimitive?.content ?: throw IllegalStateException("authorUrl is missing"), + username = extra["username"]?.jsonPrimitive?.contentOrNull, + userHandle = extra["userHandle"]?.jsonPrimitive?.contentOrNull, + channelId = extra["channelId"]?.jsonPrimitive?.contentOrNull, + target = NewsFeedConfig.getTargetFromCursorRow(cursor), + color = NewsFeedConfig.getColorFromCursorRow(cursor), + lang = NewsFeedConfig.getLangFromCursorRow(cursor), + severity = NewsFeedConfig.getSeverityFromCursorRow(cursor), + noteworthy = NewsFeedConfig.getNoteworthyFromCursorRow(cursor), + ) + } + } + + override fun toCursorRow(): Array { + return makeCursorRow( + type = NewsType.YOUTUBE, + extra = Json.encodeToString( + buildJsonObject { + put("authorUrl", authorUrl) + username?.let { put("username", it) } + userHandle?.let { put("userHandle", it) } + channelId?.let { put("channelId", it) } + } + ) + ) + } + + override fun fromCursorRow(row: Array): NewsFeedConfig { + val extraFromCursorRow = NewsFeedConfig.getExtraFromCursorRow(row) ?: throw IllegalStateException("Extra is missing") + val extra = Json.parseToJsonElement(extraFromCursorRow).jsonObject + return YouTubeNewsFeedConfig( + authorUrl = extra["authorUrl"]?.jsonPrimitive?.content ?: throw IllegalStateException("authorUrl is missing"), + username = extra["username"]?.jsonPrimitive?.contentOrNull, + userHandle = extra["userHandle"]?.jsonPrimitive?.contentOrNull, + channelId = extra["channelId"]?.jsonPrimitive?.contentOrNull, + target = NewsFeedConfig.getTargetFromCursorRow(row), + color = NewsFeedConfig.getColorFromCursorRow(row), + lang = NewsFeedConfig.getLangFromCursorRow(row), + severity = NewsFeedConfig.getSeverityFromCursorRow(row), + noteworthy = NewsFeedConfig.getNoteworthyFromCursorRow(row), + ) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/config/news/youtube/YouTubeNewsProviderConfig.kt b/src/main/java/org/mtransit/android/commons/provider/config/news/youtube/YouTubeNewsProviderConfig.kt new file mode 100644 index 00000000..4671c324 --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/config/news/youtube/YouTubeNewsProviderConfig.kt @@ -0,0 +1,17 @@ +package org.mtransit.android.commons.provider.config.news.youtube + +import android.database.Cursor +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig +import org.mtransit.android.commons.provider.config.news.NewsType + +data class YouTubeNewsProviderConfig( + override val newsFeedConfigs: List +) : NewsProviderConfig { + override val type = NewsType.YOUTUBE + + companion object { + fun fromCursor(cursor: Cursor)= YouTubeNewsProviderConfig( + newsFeedConfigs = YouTubeNewsFeedConfig.fromCursor(cursor) + ) + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/news/rss/RssNewProviderUtils.kt b/src/main/java/org/mtransit/android/commons/provider/news/rss/RssNewProviderUtils.kt index 35323cbc..3a7a8287 100644 --- a/src/main/java/org/mtransit/android/commons/provider/news/rss/RssNewProviderUtils.kt +++ b/src/main/java/org/mtransit/android/commons/provider/news/rss/RssNewProviderUtils.kt @@ -7,6 +7,9 @@ import org.mtransit.android.commons.LocaleUtils import org.mtransit.android.commons.MTLog import org.mtransit.android.commons.R import org.mtransit.android.commons.provider.agency.AgencyUtils +import org.mtransit.android.commons.provider.config.news.NewsProviderConfig +import org.mtransit.android.commons.provider.config.news.rss.RSSNewsFeedConfig +import org.mtransit.android.commons.provider.config.news.rss.RSSNewsProviderConfig import org.mtransit.commons.dropWhile import java.net.URL @@ -16,6 +19,14 @@ object RssNewProviderUtils : MTLog.Loggable { override fun getLogTag() = LOG_TAG + private var _feeds: List? = null + + private fun getFeeds(context: Context) = _feeds + ?: context.resources.getStringArray( + R.array.rss_feeds + ).toList() + .also { _feeds = it } + private var _color: String? = null private fun getColor(context: Context) = _color @@ -30,10 +41,13 @@ object RssNewProviderUtils : MTLog.Loggable { ).toList() .also { _feedsColors = it } - @JvmStatic - fun pickColor(context: Context, i: Int) = + private fun getColorOrNull(context: Context, i: Int): String? = getFeedsColors(context).getOrNull(i)?.takeIf { it.isNotBlank() } ?: getColor(context).takeIf { it.isNotBlank() } + + @JvmStatic + fun pickColor(context: Context, i: Int) = + getColorOrNull(context, i) ?: AgencyUtils.getAgencyColor(context) ?: ColorUtils.BLACK .also { @@ -53,6 +67,14 @@ object RssNewProviderUtils : MTLog.Loggable { getFeedsAuthorName(context).getOrNull(i)?.takeIf { it.isNotBlank() } ?: AgencyUtils.getAgencyShortName(context) + private var _feedsAuthorUrl: List? = null + + private fun getFeedsAuthorUrl(context: Context) = _feedsAuthorUrl + ?: context.resources.getStringArray( + R.array.rss_feeds_author_url + ).toList() + .also { _feedsAuthorUrl = it } + private val LABEL_BLACK_LIST = listOf( "api", "assets", @@ -118,12 +140,15 @@ object RssNewProviderUtils : MTLog.Loggable { @JvmStatic fun pickTarget(context: Context, i: Int): String? { - return getFeedsTarget(context).getOrNull(i)?.takeIf { it.isNotBlank() } - ?: getTargetAuthority(context).takeIf { it.isNotBlank() } + return getTargetOrNull(context, i) ?: AgencyUtils.getAgencyAuthority(context) .takeIf { context.packageName != Constants.MAIN_APP_PACKAGE_NAME }.orEmpty() } + private fun getTargetOrNull(context: Context, i: Int) = + getFeedsTarget(context).getOrNull(i)?.takeIf { it.isNotBlank() } + ?: getTargetAuthority(context).takeIf { it.isNotBlank() } + private var _feedsSeverity: List? = null private fun getFeedsSeverity(context: Context) = _feedsSeverity @@ -190,8 +215,36 @@ object RssNewProviderUtils : MTLog.Loggable { ?: context.resources.getString(R.string.rss_encoding) .also { _encoding = it } + private var _copyToFile: Boolean? = null + + private fun getCopyToFile(context: Context) = _copyToFile + ?: context.resources.getBoolean(R.bool.rss_copy_to_file_instead_of_streaming) + .also { _copyToFile = it } + @JvmStatic fun pickEncoding(context: Context) = getEncoding(context).takeIf { it.isNotBlank() } ?: ENCODING_DEFAULT + + @JvmStatic + fun getNewsConfig(context: Context): NewsProviderConfig = RSSNewsProviderConfig( + newsFeedConfigs = getFeeds(context).mapIndexed { i, url -> + RSSNewsFeedConfig( + url = url, + label = pickLabel(url), + authorIcon = getFeedsColors(context).getOrNull(i), + authorName = getFeedsAuthorName(context).getOrNull(i), + authorUrl = getFeedsAuthorUrl(context)[i], // mandatory + encoding = pickEncoding(context), + copyToFile = getCopyToFile(context), + ignoreGUID = pickIgnoreGUID(context, i), + ignoreLink = pickIgnoreLink(context, i), + target = getTargetOrNull(context, i), + lang = pickLang(context, i), + color = getColorOrNull(context, i), + severity = getFeedsSeverity(context).getOrNull(i) ?: RSSNewsFeedConfig.SEVERITY_DEFAULT, + noteworthy = getFeedsNoteworthy(context).getOrNull(i) ?: RSSNewsFeedConfig.NOTEWORTHY_DEFAULT, + ) + } + ) } \ No newline at end of file