From b5dab2e5b46fd75af6623939dc9fad5764184ba5 Mon Sep 17 00:00:00 2001 From: bannedbook Date: Sun, 24 Jan 2021 19:03:13 +0800 Subject: [PATCH] update --- fqnews/app/build.gradle | 14 +- .../net/frju/flym/service/FetcherService.kt | 181 +++++++++--------- .../net/frju/flym/service/FetcherService.kt | 181 +++++++++--------- .../frju/flym/ui/entries/EntriesFragment.kt | 79 ++++++-- .../ui/entrydetails/EntryDetailsFragment.kt | 18 ++ .../src/main/res/layout/fragment_entries.xml | 12 +- .../res/layout/fragment_entry_details.xml | 2 +- fqnews/build.gradle | 4 +- fqnews/update.json | 2 +- gitupdate.bat | 4 +- 10 files changed, 293 insertions(+), 204 deletions(-) diff --git a/fqnews/app/build.gradle b/fqnews/app/build.gradle index 36fd647d7..5b55110d3 100644 --- a/fqnews/app/build.gradle +++ b/fqnews/app/build.gradle @@ -80,11 +80,21 @@ android { resValue 'string', 'native_adUnitId', "ca-app-pub-2194043486084479/8959992113" resValue 'string', 'interstitial_adUnitId', "ca-app-pub-2194043486084479/3248199117" } + fqnews2 { + dimension "site" + applicationId "jww.feed.fqnews2" + resValue 'string', 'applicationId', applicationId + resValue 'string', 'admob_appid', "ca-app-pub-2194043486084479~6090891748" + resValue 'string', 'banner_adUnitId', "ca-app-pub-2194043486084479/2969070238" + resValue 'string', 'native_adUnitId', "ca-app-pub-2194043486084479/2813991710" + resValue 'string', 'interstitial_adUnitId', "ca-app-pub-2194043486084479/5707748368" + } } sourceSets { fqnews.setRoot('src/fqnews') hwnews.setRoot('src/hwnews') aunews.setRoot('src/aunews') + fqnews2.setRoot('src/fqnews2') } compileOptions { sourceCompatibility javaVersion @@ -140,7 +150,7 @@ android { main.java.srcDirs += 'src/main/kotlin' } - if(getCurrentProductFlavor()=='fqnews'){ + if(getCurrentProductFlavor()=='fqnews' || getCurrentProductFlavor()=='fqnews2'){ splits { abi { enable true @@ -158,6 +168,7 @@ kapt { dependencies { fqnewsImplementation project(':core') + fqnews2Implementation project(':core') hwnewsImplementation project(':plugin') hwnewsApi "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion" @@ -206,6 +217,7 @@ dependencies { implementation 'androidx.core:core-ktx:1.3.0' implementation 'androidx.paging:paging-runtime:2.1.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'org.jsoup:jsoup:1.12.1' implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' implementation 'com.github.Tunous:SwipeActionView:1.3.0' diff --git a/fqnews/app/src/aunews/java/net/frju/flym/service/FetcherService.kt b/fqnews/app/src/aunews/java/net/frju/flym/service/FetcherService.kt index e4d0e3611..647334cb7 100644 --- a/fqnews/app/src/aunews/java/net/frju/flym/service/FetcherService.kt +++ b/fqnews/app/src/aunews/java/net/frju/flym/service/FetcherService.kt @@ -29,9 +29,9 @@ import android.net.ConnectivityManager import android.net.Uri import android.os.Build import android.os.Handler -import android.text.Html import android.util.Log import androidx.core.app.NotificationCompat +import androidx.core.text.HtmlCompat import com.rometools.rome.io.SyndFeedInput import com.rometools.rome.io.XmlReader import net.dankito.readability4j.extended.Readability4JExtended @@ -61,6 +61,7 @@ import java.net.CookiePolicy import java.util.concurrent.ExecutorCompletionService import java.util.concurrent.Executors import java.util.concurrent.TimeUnit +import kotlin.math.max class FetcherService : IntentService(FetcherService::class.java.simpleName) { @@ -73,7 +74,7 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { private val HTTP_CLIENT: OkHttpClient = OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) + .readTimeout(20, TimeUnit.SECONDS) .cookieJar(JavaNetCookieJar(COOKIE_MANAGER)) .build() @@ -116,14 +117,14 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { return } - when { - ACTION_MOBILIZE_FEEDS == action -> { - mobilizeAllEntries() - downloadAllImages() - } - ACTION_DOWNLOAD_IMAGES == action -> downloadAllImages() - else -> { // == Constants.ACTION_REFRESH_FEEDS - context.putPrefBoolean(PrefConstants.IS_REFRESHING, true) + when (action) { + ACTION_MOBILIZE_FEEDS -> { + mobilizeAllEntries() + downloadAllImages() + } + ACTION_DOWNLOAD_IMAGES -> downloadAllImages() + else -> { // == Constants.ACTION_REFRESH_FEEDS + context.putPrefBoolean(PrefConstants.IS_REFRESHING, true) val readEntriesKeepTime = context.getPrefString(PrefConstants.KEEP_TIME, "4")!!.toLong() * 86400000L val readEntriesKeepDate = if (readEntriesKeepTime > 0) System.currentTimeMillis() - readEntriesKeepTime else 0 @@ -135,21 +136,21 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { deleteOldEntries(unreadEntriesKeepDate, 0) COOKIE_MANAGER.cookieStore.removeAll() // Cookies are important for some sites, but we clean them each times - // We need to use the more recent date in order to be sure to not see old entries again - val acceptMinDate = Math.max(readEntriesKeepDate, unreadEntriesKeepDate) - - var newCount = 0 - if (feedId == 0L) { - newCount = refreshFeeds(acceptMinDate) - } else { - App.db.feedDao().findById(feedId)?.let { - try { - newCount = refreshFeed(it, acceptMinDate) - } catch (e: Exception) { - error("Can't fetch feed ${it.link}", e) - } - } - } + // We need to use the more recent date in order to be sure to not see old entries again + val acceptMinDate = max(readEntriesKeepDate, unreadEntriesKeepDate) + + var newCount = 0 + if (feedId == 0L || App.db.feedDao().findById(feedId)?.isGroup == true) { + newCount = refreshFeeds(feedId, acceptMinDate) + } else { + App.db.feedDao().findById(feedId)?.let { + try { + newCount = refreshFeed(it, acceptMinDate) + } catch (e: Exception) { + error("Can't fetch feed ${it.link}", e) + } + } + } showRefreshNotification(newCount) mobilizeAllEntries() @@ -209,7 +210,7 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { .setTicker(text) .setWhen(System.currentTimeMillis()) .setAutoCancel(true) - .setContentTitle(context.getString(R.string.app_name) +" "+ context.getString(R.string.flym_feeds)) + .setContentTitle(context.getString(R.string.flym_feeds)) .setContentText(text) context.notificationManager.notify(0, notifBuilder.build()) @@ -223,15 +224,14 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { fun shouldDownloadPictures(): Boolean { val fetchPictureMode = context.getPrefString(PrefConstants.PRELOAD_IMAGE_MODE, PrefConstants.PRELOAD_IMAGE_MODE__WIFI_ONLY) - if (context.getPrefBoolean(PrefConstants.DISPLAY_IMAGES, true)) { - if (PrefConstants.PRELOAD_IMAGE_MODE__ALWAYS == fetchPictureMode) { - return true - } else if (PrefConstants.PRELOAD_IMAGE_MODE__WIFI_ONLY == fetchPictureMode) { - if (App.context.connectivityManager.activeNetworkInfo?.type == ConnectivityManager.TYPE_WIFI) { - return true - } - } - } + if (context.getPrefBoolean(PrefConstants.DISPLAY_IMAGES, true)) { + if (PrefConstants.PRELOAD_IMAGE_MODE__ALWAYS == fetchPictureMode) { + return true + } else if (PrefConstants.PRELOAD_IMAGE_MODE__WIFI_ONLY == fetchPictureMode + && context.connectivityManager.activeNetworkInfo?.type == ConnectivityManager.TYPE_WIFI) { + return true + } + } return false } @@ -293,19 +293,19 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { Readability4JExtended(link, Jsoup.parse(input, null, link)).parse().articleContent?.html()?.let { val mobilizedHtml = HtmlUtils.improveHtmlContent(it, getBaseUrl(link)) - @Suppress("DEPRECATION") - if (entry.description == null || Html.fromHtml(mobilizedHtml).length > Html.fromHtml(entry.description).length) { // If the retrieved text is smaller than the original one, then we certainly failed... - if (downloadPictures) { - val imagesList = HtmlUtils.getImageURLs(mobilizedHtml) - if (imagesList.isNotEmpty()) { - if (entry.imageLink == null) { - entry.imageLink = HtmlUtils.getMainImageURL(imagesList) - } - imgUrlsToDownload[entry.id] = imagesList - } - } else if (entry.imageLink == null) { - entry.imageLink = HtmlUtils.getMainImageURL(mobilizedHtml) - } + val entryDescription = entry.description + if (entryDescription == null || HtmlCompat.fromHtml(mobilizedHtml, HtmlCompat.FROM_HTML_MODE_LEGACY).length > HtmlCompat.fromHtml(entryDescription, HtmlCompat.FROM_HTML_MODE_LEGACY).length) { // If the retrieved text is smaller than the original one, then we certainly failed... + if (downloadPictures) { + val imagesList = HtmlUtils.getImageURLs(mobilizedHtml) + if (imagesList.isNotEmpty()) { + if (entry.imageLink == null) { + entry.imageLink = HtmlUtils.getMainImageURL(imagesList) + } + imgUrlsToDownload[entry.id] = imagesList + } + } else if (entry.imageLink == null) { + entry.imageLink = HtmlUtils.getMainImageURL(mobilizedHtml) + } success = true @@ -359,7 +359,7 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { } } - private fun refreshFeeds(acceptMinDate: Long): Int { + private fun refreshFeeds(feedId: Long, acceptMinDate: Long): Int { val executor = Executors.newFixedThreadPool(THREAD_NUMBER) { r -> Thread(r).apply { @@ -368,29 +368,34 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { } val completionService = ExecutorCompletionService(executor) - var globalResult = 0 - - val feeds = App.db.feedDao().allNonGroupFeeds - for (feed in feeds) { - completionService.submit { - var result = 0 - try { - result = refreshFeed(feed, acceptMinDate) - } catch (e: Exception) { - error("Can't fetch feedWithCount ${feed.link}", e) - } + var globalResult = 0 + val feeds: List + if (feedId == 0L) { + feeds = App.db.feedDao().allNonGroupFeeds + } else { + feeds = App.db.feedDao().allFeedsInGroup(feedId) + } + + for (feed in feeds) { + completionService.submit { + var result = 0 + try { + result = refreshFeed(feed, acceptMinDate) + } catch (e: Exception) { + error("Can't fetch feedWithCount ${feed.link}", e) + } result } } - for (i in 0 until feeds.size) { - try { - val f = completionService.take() - globalResult += f.get() - } catch (ignored: Exception) { - } - } + for (i in feeds.indices) { + try { + val f = completionService.take() + globalResult += f.get() + } catch (ignored: Exception) { + } + } executor.shutdownNow() // To purge observeAll threads @@ -408,7 +413,7 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { createCall(feed.link).execute().use { response -> val input = SyndFeedInput() val romeFeed = input.build(XmlReader(response.body!!.byteStream())) - entries.addAll(romeFeed.entries.asSequence().filter { it.publishedDate?.time ?: Long.MAX_VALUE > acceptMinDate }.map { it.toDbFormat(feed) }) + entries.addAll(romeFeed.entries.asSequence().filter { it.publishedDate?.time ?: Long.MAX_VALUE > acceptMinDate }.map { it.toDbFormat(context, feed) }) feed.update(romeFeed) } } catch (t: Throwable) { @@ -435,15 +440,16 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { if (filterKeywordString.isNotBlank()) { val keywordLists = filterKeywordString.split(',').map { it.trim() } - if (keywordLists.isNotEmpty()) { - entries.removeAll { entry -> - keywordLists.any { - entry.title?.contains(it, true) == true || - entry.description?.contains(it, true) == true - } - } - } - } + if (keywordLists.isNotEmpty()) { + entries.removeAll { entry -> + keywordLists.any { + entry.title?.contains(it, true) == true || + entry.description?.contains(it, true) == true || + entry.author?.contains(it, true) == true + } + } + } + } val feedBaseUrl = getBaseUrl(feed.link) var foundExisting = false @@ -511,9 +517,8 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { if (!File(tempImgPath).exists() && !File(finalImgPath).exists()) { IMAGE_FOLDER_FILE.mkdir() // create images dir - // Compute the real URL (without "é", ...) - @Suppress("DEPRECATION") - val realUrl = Html.fromHtml(imgUrl).toString() + // Compute the real URL (without "é", ...) + val realUrl = HtmlCompat.fromHtml(imgUrl, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() try { createCall(realUrl).execute().use { response -> @@ -541,14 +546,14 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { // We need to exclude favorite entries images to this cleanup val favoriteIds = App.db.entryDao().favoriteIds - IMAGE_FOLDER_FILE.listFiles().forEach { file -> - // If old file and not part of a favorite entry - if (file.lastModified() < keepDateBorderTime && !favoriteIds.any { file.name.startsWith(it + ID_SEPARATOR) }) { - file.delete() - } - } - } - } + IMAGE_FOLDER_FILE.listFiles()?.forEach { file -> + // If old file and not part of a favorite entry + if (file.lastModified() < keepDateBorderTime && !favoriteIds.any { file.name.startsWith(it + ID_SEPARATOR) }) { + file.delete() + } + } + } + } private fun getBaseUrl(link: String): String { var baseUrl = link diff --git a/fqnews/app/src/hwnews/java/net/frju/flym/service/FetcherService.kt b/fqnews/app/src/hwnews/java/net/frju/flym/service/FetcherService.kt index e4d0e3611..647334cb7 100644 --- a/fqnews/app/src/hwnews/java/net/frju/flym/service/FetcherService.kt +++ b/fqnews/app/src/hwnews/java/net/frju/flym/service/FetcherService.kt @@ -29,9 +29,9 @@ import android.net.ConnectivityManager import android.net.Uri import android.os.Build import android.os.Handler -import android.text.Html import android.util.Log import androidx.core.app.NotificationCompat +import androidx.core.text.HtmlCompat import com.rometools.rome.io.SyndFeedInput import com.rometools.rome.io.XmlReader import net.dankito.readability4j.extended.Readability4JExtended @@ -61,6 +61,7 @@ import java.net.CookiePolicy import java.util.concurrent.ExecutorCompletionService import java.util.concurrent.Executors import java.util.concurrent.TimeUnit +import kotlin.math.max class FetcherService : IntentService(FetcherService::class.java.simpleName) { @@ -73,7 +74,7 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { private val HTTP_CLIENT: OkHttpClient = OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(10, TimeUnit.SECONDS) + .readTimeout(20, TimeUnit.SECONDS) .cookieJar(JavaNetCookieJar(COOKIE_MANAGER)) .build() @@ -116,14 +117,14 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { return } - when { - ACTION_MOBILIZE_FEEDS == action -> { - mobilizeAllEntries() - downloadAllImages() - } - ACTION_DOWNLOAD_IMAGES == action -> downloadAllImages() - else -> { // == Constants.ACTION_REFRESH_FEEDS - context.putPrefBoolean(PrefConstants.IS_REFRESHING, true) + when (action) { + ACTION_MOBILIZE_FEEDS -> { + mobilizeAllEntries() + downloadAllImages() + } + ACTION_DOWNLOAD_IMAGES -> downloadAllImages() + else -> { // == Constants.ACTION_REFRESH_FEEDS + context.putPrefBoolean(PrefConstants.IS_REFRESHING, true) val readEntriesKeepTime = context.getPrefString(PrefConstants.KEEP_TIME, "4")!!.toLong() * 86400000L val readEntriesKeepDate = if (readEntriesKeepTime > 0) System.currentTimeMillis() - readEntriesKeepTime else 0 @@ -135,21 +136,21 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { deleteOldEntries(unreadEntriesKeepDate, 0) COOKIE_MANAGER.cookieStore.removeAll() // Cookies are important for some sites, but we clean them each times - // We need to use the more recent date in order to be sure to not see old entries again - val acceptMinDate = Math.max(readEntriesKeepDate, unreadEntriesKeepDate) - - var newCount = 0 - if (feedId == 0L) { - newCount = refreshFeeds(acceptMinDate) - } else { - App.db.feedDao().findById(feedId)?.let { - try { - newCount = refreshFeed(it, acceptMinDate) - } catch (e: Exception) { - error("Can't fetch feed ${it.link}", e) - } - } - } + // We need to use the more recent date in order to be sure to not see old entries again + val acceptMinDate = max(readEntriesKeepDate, unreadEntriesKeepDate) + + var newCount = 0 + if (feedId == 0L || App.db.feedDao().findById(feedId)?.isGroup == true) { + newCount = refreshFeeds(feedId, acceptMinDate) + } else { + App.db.feedDao().findById(feedId)?.let { + try { + newCount = refreshFeed(it, acceptMinDate) + } catch (e: Exception) { + error("Can't fetch feed ${it.link}", e) + } + } + } showRefreshNotification(newCount) mobilizeAllEntries() @@ -209,7 +210,7 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { .setTicker(text) .setWhen(System.currentTimeMillis()) .setAutoCancel(true) - .setContentTitle(context.getString(R.string.app_name) +" "+ context.getString(R.string.flym_feeds)) + .setContentTitle(context.getString(R.string.flym_feeds)) .setContentText(text) context.notificationManager.notify(0, notifBuilder.build()) @@ -223,15 +224,14 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { fun shouldDownloadPictures(): Boolean { val fetchPictureMode = context.getPrefString(PrefConstants.PRELOAD_IMAGE_MODE, PrefConstants.PRELOAD_IMAGE_MODE__WIFI_ONLY) - if (context.getPrefBoolean(PrefConstants.DISPLAY_IMAGES, true)) { - if (PrefConstants.PRELOAD_IMAGE_MODE__ALWAYS == fetchPictureMode) { - return true - } else if (PrefConstants.PRELOAD_IMAGE_MODE__WIFI_ONLY == fetchPictureMode) { - if (App.context.connectivityManager.activeNetworkInfo?.type == ConnectivityManager.TYPE_WIFI) { - return true - } - } - } + if (context.getPrefBoolean(PrefConstants.DISPLAY_IMAGES, true)) { + if (PrefConstants.PRELOAD_IMAGE_MODE__ALWAYS == fetchPictureMode) { + return true + } else if (PrefConstants.PRELOAD_IMAGE_MODE__WIFI_ONLY == fetchPictureMode + && context.connectivityManager.activeNetworkInfo?.type == ConnectivityManager.TYPE_WIFI) { + return true + } + } return false } @@ -293,19 +293,19 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { Readability4JExtended(link, Jsoup.parse(input, null, link)).parse().articleContent?.html()?.let { val mobilizedHtml = HtmlUtils.improveHtmlContent(it, getBaseUrl(link)) - @Suppress("DEPRECATION") - if (entry.description == null || Html.fromHtml(mobilizedHtml).length > Html.fromHtml(entry.description).length) { // If the retrieved text is smaller than the original one, then we certainly failed... - if (downloadPictures) { - val imagesList = HtmlUtils.getImageURLs(mobilizedHtml) - if (imagesList.isNotEmpty()) { - if (entry.imageLink == null) { - entry.imageLink = HtmlUtils.getMainImageURL(imagesList) - } - imgUrlsToDownload[entry.id] = imagesList - } - } else if (entry.imageLink == null) { - entry.imageLink = HtmlUtils.getMainImageURL(mobilizedHtml) - } + val entryDescription = entry.description + if (entryDescription == null || HtmlCompat.fromHtml(mobilizedHtml, HtmlCompat.FROM_HTML_MODE_LEGACY).length > HtmlCompat.fromHtml(entryDescription, HtmlCompat.FROM_HTML_MODE_LEGACY).length) { // If the retrieved text is smaller than the original one, then we certainly failed... + if (downloadPictures) { + val imagesList = HtmlUtils.getImageURLs(mobilizedHtml) + if (imagesList.isNotEmpty()) { + if (entry.imageLink == null) { + entry.imageLink = HtmlUtils.getMainImageURL(imagesList) + } + imgUrlsToDownload[entry.id] = imagesList + } + } else if (entry.imageLink == null) { + entry.imageLink = HtmlUtils.getMainImageURL(mobilizedHtml) + } success = true @@ -359,7 +359,7 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { } } - private fun refreshFeeds(acceptMinDate: Long): Int { + private fun refreshFeeds(feedId: Long, acceptMinDate: Long): Int { val executor = Executors.newFixedThreadPool(THREAD_NUMBER) { r -> Thread(r).apply { @@ -368,29 +368,34 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { } val completionService = ExecutorCompletionService(executor) - var globalResult = 0 - - val feeds = App.db.feedDao().allNonGroupFeeds - for (feed in feeds) { - completionService.submit { - var result = 0 - try { - result = refreshFeed(feed, acceptMinDate) - } catch (e: Exception) { - error("Can't fetch feedWithCount ${feed.link}", e) - } + var globalResult = 0 + val feeds: List + if (feedId == 0L) { + feeds = App.db.feedDao().allNonGroupFeeds + } else { + feeds = App.db.feedDao().allFeedsInGroup(feedId) + } + + for (feed in feeds) { + completionService.submit { + var result = 0 + try { + result = refreshFeed(feed, acceptMinDate) + } catch (e: Exception) { + error("Can't fetch feedWithCount ${feed.link}", e) + } result } } - for (i in 0 until feeds.size) { - try { - val f = completionService.take() - globalResult += f.get() - } catch (ignored: Exception) { - } - } + for (i in feeds.indices) { + try { + val f = completionService.take() + globalResult += f.get() + } catch (ignored: Exception) { + } + } executor.shutdownNow() // To purge observeAll threads @@ -408,7 +413,7 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { createCall(feed.link).execute().use { response -> val input = SyndFeedInput() val romeFeed = input.build(XmlReader(response.body!!.byteStream())) - entries.addAll(romeFeed.entries.asSequence().filter { it.publishedDate?.time ?: Long.MAX_VALUE > acceptMinDate }.map { it.toDbFormat(feed) }) + entries.addAll(romeFeed.entries.asSequence().filter { it.publishedDate?.time ?: Long.MAX_VALUE > acceptMinDate }.map { it.toDbFormat(context, feed) }) feed.update(romeFeed) } } catch (t: Throwable) { @@ -435,15 +440,16 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { if (filterKeywordString.isNotBlank()) { val keywordLists = filterKeywordString.split(',').map { it.trim() } - if (keywordLists.isNotEmpty()) { - entries.removeAll { entry -> - keywordLists.any { - entry.title?.contains(it, true) == true || - entry.description?.contains(it, true) == true - } - } - } - } + if (keywordLists.isNotEmpty()) { + entries.removeAll { entry -> + keywordLists.any { + entry.title?.contains(it, true) == true || + entry.description?.contains(it, true) == true || + entry.author?.contains(it, true) == true + } + } + } + } val feedBaseUrl = getBaseUrl(feed.link) var foundExisting = false @@ -511,9 +517,8 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { if (!File(tempImgPath).exists() && !File(finalImgPath).exists()) { IMAGE_FOLDER_FILE.mkdir() // create images dir - // Compute the real URL (without "é", ...) - @Suppress("DEPRECATION") - val realUrl = Html.fromHtml(imgUrl).toString() + // Compute the real URL (without "é", ...) + val realUrl = HtmlCompat.fromHtml(imgUrl, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() try { createCall(realUrl).execute().use { response -> @@ -541,14 +546,14 @@ class FetcherService : IntentService(FetcherService::class.java.simpleName) { // We need to exclude favorite entries images to this cleanup val favoriteIds = App.db.entryDao().favoriteIds - IMAGE_FOLDER_FILE.listFiles().forEach { file -> - // If old file and not part of a favorite entry - if (file.lastModified() < keepDateBorderTime && !favoriteIds.any { file.name.startsWith(it + ID_SEPARATOR) }) { - file.delete() - } - } - } - } + IMAGE_FOLDER_FILE.listFiles()?.forEach { file -> + // If old file and not part of a favorite entry + if (file.lastModified() < keepDateBorderTime && !favoriteIds.any { file.name.startsWith(it + ID_SEPARATOR) }) { + file.delete() + } + } + } + } private fun getBaseUrl(link: String): String { var baseUrl = link diff --git a/fqnews/app/src/main/java/net/frju/flym/ui/entries/EntriesFragment.kt b/fqnews/app/src/main/java/net/frju/flym/ui/entries/EntriesFragment.kt index 667dab26e..63c9efcf8 100644 --- a/fqnews/app/src/main/java/net/frju/flym/ui/entries/EntriesFragment.kt +++ b/fqnews/app/src/main/java/net/frju/flym/ui/entries/EntriesFragment.kt @@ -24,6 +24,7 @@ import android.net.Uri import android.os.Bundle import android.os.Handler import android.text.TextUtils +import android.util.DisplayMetrics import android.util.Log import android.view.* import android.widget.* @@ -44,9 +45,13 @@ import com.google.android.gms.ads.* import com.google.android.gms.ads.formats.NativeAdOptions import com.google.android.gms.ads.formats.UnifiedNativeAd import com.google.android.gms.ads.formats.UnifiedNativeAdView +import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.fragment_entries.* +import kotlinx.android.synthetic.main.fragment_entries.refresh_layout +import kotlinx.android.synthetic.main.fragment_entry_details.* import kotlinx.android.synthetic.main.view_entry.view.* import kotlinx.android.synthetic.main.view_main_containers.* +import kotlinx.android.synthetic.main.view_main_containers.toolbar import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import net.fred.feedex.R @@ -111,34 +116,22 @@ class EntriesFragment : Fragment() { private fun tryBindAd() = lifecycleScope.launchWhenStarted { if(layoutManager==null)return@launchWhenStarted try { - val fp = layoutManager!!.findFirstVisibleItemPosition() - - if (fp < 0) return@launchWhenStarted - for (i in object : Iterator { - var first = fp - var last = layoutManager!!.findLastCompletelyVisibleItemPosition() - var flipper = false - override fun hasNext() = first <= last - override fun next(): Int { - flipper = !flipper - return if (flipper) first++ else last-- - } - }.asSequence().toList().reversed()) { + + //val fp = layoutManager!!.findFirstVisibleItemPosition() + val fp = 0 try { - var viewHolder = recycler_view.findViewHolderForAdapterPosition(i) - if(viewHolder==null)continue + var viewHolder: RecyclerView.ViewHolder? = recycler_view.findViewHolderForAdapterPosition(fp) + ?: return@launchWhenStarted viewHolder = viewHolder as ViewHolder - if (i<5) { + if (fp==0) { viewHolder.populateUnifiedNativeAdView(nativeAd!!, nativeAdView!!) // might be in the middle of a layout after scrolling, need to wait - withContext(Dispatchers.Main) { adapter.notifyItemChanged(i) } - break + withContext(Dispatchers.Main) { adapter.notifyItemChanged(fp) } } }catch (ex: Exception){ Log.e("ssvpn", ex.message, ex) - continue } - } + }catch (e: Exception){ Log.e("ssvpn", e.message, e) } @@ -265,6 +258,50 @@ class EntriesFragment : Fragment() { MobileAds.initialize(activity, activity?.getString(R.string.admob_appid)) mInterstitialAd = InterstitialAd(activity) mInterstitialAd.adUnitId = activity?.getString(R.string.interstitial_adUnitId) + + //MobileAds.initialize(activity) {} + adView = AdView(activity) + list_ad_view_container = requireActivity().findViewById(R.id.list_ad_view_container) + list_ad_view_container.addView(adView) + // Since we're loading the banner based on the adContainerView size, we need to wait until this + // view is laid out before we can get the width. + list_ad_view_container.viewTreeObserver.addOnGlobalLayoutListener { + if (!initialLayoutComplete) { + initialLayoutComplete = true + loadBanner() + //val adsHeight: Int = adView.adSize.getHeightInPixels(activity) + //swipe_view.bottomPadding = adsHeight + 5 + } + } + } + + private lateinit var adView: AdView + private var initialLayoutComplete = false + private lateinit var list_ad_view_container: FrameLayout + // Determine the screen width (less decorations) to use for the ad width. + // If the ad hasn't been laid out, default to the full screen width. + private val adSize: AdSize + get() { + val display = activity?.windowManager?.defaultDisplay + val outMetrics = DisplayMetrics() + display?.getMetrics(outMetrics) + val density = outMetrics.density + var adWidthPixels = list_ad_view_container.width.toFloat() + if (adWidthPixels == 0f) { + adWidthPixels = outMetrics.widthPixels.toFloat() + } + + val adWidth = (adWidthPixels / density).toInt() + return AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(activity, adWidth) + } + private fun loadBanner() { + adView.adUnitId=getString(R.string.banner_adUnitId) + adView.adSize = adSize + // Log.e("adSize",adView.adSize.width.toString()+","+adView.adSize.height.toString()) + // Create an ad request. + val adRequest = AdRequest.Builder().build() + // Start loading the ad in the background. + adView.loadAd(adRequest) } private fun initDataObservers() { @@ -649,6 +686,8 @@ class EntriesFragment : Fragment() { intent.action = Intent.ACTION_VIEW intent.addCategory(Intent.CATEGORY_BROWSABLE) intent.data = Uri.parse("https://github.com/bannedbook/fanqiang/wiki/V2ray%E6%9C%BA%E5%9C%BA") + //fqnews2 + //intent.data = Uri.parse("https://github.com/vpn69/tea/blob/main/V2Ray%E6%9C%BA%E5%9C%BA%E6%8E%A8%E8%8D%90.md") startActivity(intent) } adContainer.addView(imageBannerView) diff --git a/fqnews/app/src/main/java/net/frju/flym/ui/entrydetails/EntryDetailsFragment.kt b/fqnews/app/src/main/java/net/frju/flym/ui/entrydetails/EntryDetailsFragment.kt index 8443920d5..fa403792e 100644 --- a/fqnews/app/src/main/java/net/frju/flym/ui/entrydetails/EntryDetailsFragment.kt +++ b/fqnews/app/src/main/java/net/frju/flym/ui/entrydetails/EntryDetailsFragment.kt @@ -18,12 +18,14 @@ package net.frju.flym.ui.entrydetails import android.content.Intent +import android.net.Uri import android.os.Bundle import android.util.DisplayMetrics import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ImageView import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -348,6 +350,22 @@ class EntryDetailsFragment : Fragment() { } } } + else{ + val imageBannerView = ImageView(activity) + imageBannerView.setImageResource(R.drawable.v2free) + imageBannerView.setOnClickListener{ + val intent = Intent() + intent.action = Intent.ACTION_VIEW + intent.addCategory(Intent.CATEGORY_BROWSABLE) + intent.data = Uri.parse("https://github.com/bannedbook/fanqiang/wiki/V2ray%E6%9C%BA%E5%9C%BA") + //fqnews2 + //intent.data = Uri.parse("https://github.com/vpn69/tea/blob/main/V2Ray%E6%9C%BA%E5%9C%BA%E6%8E%A8%E8%8D%90.md") + startActivity(intent) + } + ad_view_container.addView(imageBannerView) + val adsHeight: Int = imageBannerView.drawable.intrinsicHeight + swipe_view.bottomPadding = adsHeight + 5 + } } catch (e: Exception) { //e.printStackTrace() Log.e("ads---", e.message) diff --git a/fqnews/app/src/main/res/layout/fragment_entries.xml b/fqnews/app/src/main/res/layout/fragment_entries.xml index f2e3f9e98..236c62a36 100644 --- a/fqnews/app/src/main/res/layout/fragment_entries.xml +++ b/fqnews/app/src/main/res/layout/fragment_entries.xml @@ -11,7 +11,7 @@ android:layout_marginEnd="0dp" android:layout_marginStart="0dp" android:layout_marginTop="0dp" - app:layout_constraintBottom_toTopOf="@+id/bottom_navigation" + app:layout_constraintBottom_toTopOf="@+id/list_ad_view_container" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -50,6 +50,16 @@ android:src="@drawable/ic_read_all_white_24dp" /> + +