From a7b4b5ffb16006f15977820315078fde40475622 Mon Sep 17 00:00:00 2001 From: AlbatovK Date: Thu, 22 Jul 2021 13:32:17 +0600 Subject: [PATCH] ommit --- .idea/compiler.xml | 2 +- .idea/dictionaries/User.xml | 1 + .idea/misc.xml | 2 +- .idea/runConfigurations.xml | 10 ++ app/build.gradle | 6 +- app/src/main/AndroidManifest.xml | 19 ++- app/src/main/assets/sites_table.sql | 7 +- .../project_28_02_2021/LikedNewsActivity.java | 153 ----------------- .../project_28_02_2021/NewsRssItem.java | 157 ------------------ .../example/project_28_02_2021/RssParser.java | 73 -------- .../project_28_02_2021/SendingWorker.java | 123 -------------- .../com/example/project_28_02_2021/Site.java | 85 ---------- .../project_28_02_2021/SplashActivity.java | 72 -------- .../activity/LikedNewsActivity.java | 110 ++++++++++++ .../{ => activity}/MainActivity.java | 110 +++++++----- .../{ => activity}/SettingsActivity.java | 69 ++++++-- .../activity/SplashActivity.java | 63 +++++++ .../notification/ConnectionWorker.java | 114 +++++++++++++ .../notification/SendingWorker.java | 116 +++++++++++++ .../notification/interfaces/ISend.java | 10 ++ .../rss/ItemComparators.java | 7 + .../project_28_02_2021/rss/NewsRssItem.java | 95 +++++++++++ .../rss/NewsRssItemManager.java | 43 +++++ .../{ => rss/adapter}/NewsRssItemAdapter.java | 62 +++---- .../example/project_28_02_2021/site/Site.java | 46 +++++ .../project_28_02_2021/site/SiteManager.java | 44 +++++ .../site/SiteStatusStates.java | 7 + .../{ => site/adapter}/SiteAdapter.java | 49 ++---- .../{ => util/database}/DataBaseHelper.java | 46 +++-- .../util/files/FileManager.java | 47 ++++++ .../util/net/NetLoader.java | 53 ++++++ .../settings}/PreferenceManager.java | 28 ++-- .../util/xml/XmlCreator.java | 4 + .../util/xml/XmlFeedParser.java | 53 ++++++ .../main/res/layout/activity_favorites.xml | 36 ++++ .../layout/activity_liked_news_activity.xml | 17 -- app/src/main/res/layout/activity_main.xml | 3 +- app/src/main/res/layout/activity_settings.xml | 18 +- app/src/main/res/layout/activity_splash.xml | 2 +- app/src/main/res/layout/favorites_footer.xml | 22 +++ app/src/main/res/layout/favorites_header.xml | 23 +++ app/src/main/res/values/strings.xml | 5 + build.gradle | 6 +- 43 files changed, 1143 insertions(+), 875 deletions(-) create mode 100644 .idea/runConfigurations.xml delete mode 100644 app/src/main/java/com/example/project_28_02_2021/LikedNewsActivity.java delete mode 100644 app/src/main/java/com/example/project_28_02_2021/NewsRssItem.java delete mode 100644 app/src/main/java/com/example/project_28_02_2021/RssParser.java delete mode 100644 app/src/main/java/com/example/project_28_02_2021/SendingWorker.java delete mode 100644 app/src/main/java/com/example/project_28_02_2021/Site.java delete mode 100644 app/src/main/java/com/example/project_28_02_2021/SplashActivity.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/activity/LikedNewsActivity.java rename app/src/main/java/com/example/project_28_02_2021/{ => activity}/MainActivity.java (75%) rename app/src/main/java/com/example/project_28_02_2021/{ => activity}/SettingsActivity.java (70%) create mode 100644 app/src/main/java/com/example/project_28_02_2021/activity/SplashActivity.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/notification/ConnectionWorker.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/notification/SendingWorker.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/notification/interfaces/ISend.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/rss/ItemComparators.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/rss/NewsRssItem.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/rss/NewsRssItemManager.java rename app/src/main/java/com/example/project_28_02_2021/{ => rss/adapter}/NewsRssItemAdapter.java (85%) create mode 100644 app/src/main/java/com/example/project_28_02_2021/site/Site.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/site/SiteManager.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/site/SiteStatusStates.java rename app/src/main/java/com/example/project_28_02_2021/{ => site/adapter}/SiteAdapter.java (52%) rename app/src/main/java/com/example/project_28_02_2021/{ => util/database}/DataBaseHelper.java (54%) create mode 100644 app/src/main/java/com/example/project_28_02_2021/util/files/FileManager.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/util/net/NetLoader.java rename app/src/main/java/com/example/project_28_02_2021/{ => util/settings}/PreferenceManager.java (72%) create mode 100644 app/src/main/java/com/example/project_28_02_2021/util/xml/XmlCreator.java create mode 100644 app/src/main/java/com/example/project_28_02_2021/util/xml/XmlFeedParser.java create mode 100644 app/src/main/res/layout/activity_favorites.xml delete mode 100644 app/src/main/res/layout/activity_liked_news_activity.xml create mode 100644 app/src/main/res/layout/favorites_footer.xml create mode 100644 app/src/main/res/layout/favorites_header.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 61a9130..fb7f4a8 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/dictionaries/User.xml b/.idea/dictionaries/User.xml index 2419f10..9186c5d 100644 --- a/.idea/dictionaries/User.xml +++ b/.idea/dictionaries/User.xml @@ -3,6 +3,7 @@ descr habr + habrahabr ixbt metanit mobi diff --git a/.idea/misc.xml b/.idea/misc.xml index 81ce769..e224cb0 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -44,7 +44,7 @@ - + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..797acea --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index e50b4eb..517e2b3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,13 +33,9 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'org.jsoup:jsoup:1.13.1' implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" - implementation 'androidx.navigation:navigation-fragment:2.3.5' - implementation 'androidx.navigation:navigation-ui:2.3.5' - implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' implementation 'androidx.preference:preference:1.1.1' + implementation 'org.jsoup:jsoup:1.13.1' implementation 'androidx.work:work-runtime:2.5.0' implementation 'com.squareup.picasso:picasso:2.5.2' testImplementation 'junit:junit:4.13.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 220f920..ee5d25c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,31 +22,34 @@ tools:ignore="AllowBackup" tools:targetApi="m"> - + + + android:parentActivityName=".activity.MainActivity"> + android:value=".activity.MainActivity" /> + + android:value=".activity.MainActivity" /> + - + \ No newline at end of file diff --git a/app/src/main/assets/sites_table.sql b/app/src/main/assets/sites_table.sql index 90c946b..1720820 100644 --- a/app/src/main/assets/sites_table.sql +++ b/app/src/main/assets/sites_table.sql @@ -1,7 +1,8 @@ insert into sites_table (name, url) values ('Habr', 'https://habr.com/ru/rss/all/all'); -insert into sites_table (name, url) values ('Hi-News', 'https://hi-news.ru/feed'); +insert into sites_table (name, url) values ('HiNews', 'https://hi-news.ru/feed'); insert into sites_table (name, url) values ('Ixbt News', 'https://www.ixbt.com/export/news.rss'); -insert into sites_table (name, url) values ('Новости Ай-Ти', 'https://novostit.com/feed'); +insert into sites_table (name, url) values ('Новости IT', 'https://novostit.com/feed'); insert into sites_table (name, url) values ('BBC Tech', 'http://feeds.bbci.co.uk/news/technology/rss.xml'); insert into sites_table (name, url) values ('BBC News', 'http://feeds.bbci.co.uk/news/world/rss.xml'); -insert into sites_table (name, url) values ('Лента.Ру', 'https://lenta.ru/rss/top7') \ No newline at end of file +insert into sites_table (name, url) values ('Лента.Ру', 'https://lenta.ru/rss/top7'); +insert into sites_table (name, url) values ('Habrahabr', 'https://habrahabr.ru/rss/hubs'); \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/LikedNewsActivity.java b/app/src/main/java/com/example/project_28_02_2021/LikedNewsActivity.java deleted file mode 100644 index cfa4641..0000000 --- a/app/src/main/java/com/example/project_28_02_2021/LikedNewsActivity.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.example.project_28_02_2021; - -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ListView; - -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.parser.Parser; -import org.jsoup.select.Elements; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.Comparator; -import java.util.Scanner; - -public class LikedNewsActivity extends AppCompatActivity { - - private ListView listView = null; - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.delete_liked_list_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.delete_all) { - NewsRssItem.getLikedNews().clear(); - deleteFile("news.xml"); - setDefaultSettings(); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - getMenuInflater().inflate(R.menu.liked_list_menu, menu); - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); - if (item.getItemId() == R.id.liked_share) { - Intent shareIntent = new Intent(); - shareIntent.setAction(Intent.ACTION_SEND); - shareIntent.putExtra(Intent.EXTRA_TEXT, NewsRssItem.getNews().get(info.position).getLink()); - shareIntent.setType("text/plain"); - startActivity(shareIntent); - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - AlertDialog alertDialog = builder - .setTitle(R.string.str_delete_liked) - .setMessage(R.string.str_sure_delete_liked) - .setNegativeButton(R.string.str_add_site_neg_button, - (dialog, which) -> closeOptionsMenu()) - .setPositiveButton(R.string.str_delete_site, - (dialog, which) -> { - NewsRssItem removedItem = NewsRssItem.getLikedNews().get(info.position); - StringBuilder gotXml = new StringBuilder(); - try (InputStream inputStream = openFileInput("news.xml")) { - Scanner scanner = new Scanner(inputStream); - while (scanner.hasNext()) { - gotXml.append(scanner.nextLine()); - } - } catch (IOException ignored) { - } - deleteFile("news.xml"); - Document doc = Jsoup.parse(gotXml.toString(), "", Parser.xmlParser()); - Elements items = doc.select("item"); - StringBuilder resXml = new StringBuilder(); - String root = ""; - String startTag = ""; - String endTag = ""; - try { - for (Element docItem : items) { - if (docItem.select("title").text().equals(removedItem.getTitle())) { - continue; - } - resXml.append(docItem.toString()); - } - } catch (Exception ignored) { - } - String res = root + startTag + resXml.toString() + endTag; - try { - openFileOutput("news.xml", MODE_APPEND).write(res.getBytes()); - } catch (IOException ignored) { - } - NewsRssItem.getLikedNews().remove(info.position); - listView.setAdapter(new NewsRssItemAdapter(this, - R.layout.list_item_layout, NewsRssItem.getLikedNews(), false)); - }) - .create(); - alertDialog.show(); - } - return true; - } - - public void setDefaultSettings() { - SharedPreferences settings = getSharedPreferences(PreferenceManager.SETTINGS_NAME, MODE_MULTI_PROCESS); - AdapterView.OnItemClickListener itemListener = - (parent, view, position, id) -> startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse(NewsRssItem.getLikedNews().get(position).getLink()))); - listView.setOnItemClickListener(itemListener); - Comparator defaultComparator; - switch (settings.getString(PreferenceManager.SORT_KEY, PreferenceManager.SORT_BY_DATE)) { - case PreferenceManager.SORT_BY_DATE: - defaultComparator = NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_DATE); - break; - case PreferenceManager.SORT_BY_SITE: - defaultComparator = NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_SITE); - break; - case PreferenceManager.SORT_BY_SIZE: - defaultComparator = NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_SIZE); - break; - default: - defaultComparator = (n_1, n_2) -> 0; - } - Collections.sort(NewsRssItem.getLikedNews(), defaultComparator); - listView.setAdapter(new NewsRssItemAdapter(this, - R.layout.list_item_layout, NewsRssItem.getLikedNews(), false)); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_liked_news_activity); - ActionBar bar = getSupportActionBar(); - if (bar != null) { - bar.setDisplayHomeAsUpEnabled(true); - } - listView = findViewById(R.id.liked_news_list); - setDefaultSettings(); - registerForContextMenu(listView); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/NewsRssItem.java b/app/src/main/java/com/example/project_28_02_2021/NewsRssItem.java deleted file mode 100644 index d1a521c..0000000 --- a/app/src/main/java/com/example/project_28_02_2021/NewsRssItem.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.example.project_28_02_2021; - -import android.content.Context; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Comparator; -import java.util.Date; -import java.util.HashSet; -import java.util.Locale; - -public class NewsRssItem { - - private static final ArrayList news = new ArrayList<>(); - private static final ArrayList likedNews = new ArrayList<>(); - - private final Site site; - private final String link; - private final String title; - private final String urlImage; - private final HashSet categoryWords = new HashSet<>(); - private final Context context; - private Date pubDate; - - public NewsRssItem(Site site, String link, String title, - String categoryData, String pubDate, String urlImage, - Context context) { - this.site = site; - this.link = link; - this.title = title; - this.urlImage = urlImage; - this.context = context; - - String letters = ",.:-[{}]&*@!?;\"'#$%^()+-=><|\\/~`"; - StringBuilder builder = new StringBuilder(); - char[] chars = categoryData.concat(title.toLowerCase()).trim().toCharArray(); - for (char letter : chars) { - if (letter == ' ') { - categoryWords.add(builder.toString().trim()); - builder = new StringBuilder(); - } else { - boolean isValid = true; - for (char ch : letters.toCharArray()) { - if (ch == letter) { - isValid = false; - break; - } - } - if (!isValid) { - continue; - } - } - builder.append(letter); - } - categoryWords.add(builder.toString().trim()); - categoryWords.add(site.getName().trim().toLowerCase()); - String s_format_simple = "E, d MMM yyyy H:m:s z"; - String s_format_updated = "E MMM dd HH:mm:ss z yyyy"; - try { - this.pubDate = new SimpleDateFormat(s_format_simple, Locale.US). - parse(pubDate); - } catch (ParseException ignored) { - try { - this.pubDate = new SimpleDateFormat(s_format_updated, Locale.US). - parse(pubDate); - } catch (ParseException anIgnored) { - this.pubDate = new Date(System.currentTimeMillis()); - } - } - } - - public enum ItemComparators { - SORT_BY_SIZE, - SORT_BY_SITE, - SORT_BY_DATE, - } - - public static Comparator getComparator(ItemComparators type) { - Comparator itemComparator = (n_1, n_2) -> 0; - switch (type) { - case SORT_BY_SIZE: - itemComparator = (n_1, n_2) -> - Integer.compare(n_2.getTitle().length(), n_1.getTitle().length()); - break; - case SORT_BY_SITE: - itemComparator = (n_1, n_2) -> - n_1.getSite().getName().compareToIgnoreCase(n_2.getSite().getName()); - break; - case SORT_BY_DATE: - itemComparator = (n_1, n_2) -> - n_2.getDate().compareTo(n_1.getDate()); - break; - } - return itemComparator; - } - - public String getRegexDate() { - long nowDate = Calendar.getInstance().getTimeInMillis(); - double time = (double) (nowDate - pubDate.getTime()) / (1000 * 60 * 60 * 24); - String date = (int) time + " " - + context.getResources().getQuantityString(R.plurals.day_plurals, (int) time); - if (time < 1) { - time = (double) (nowDate - pubDate.getTime()) / (1000 * 60 * 60); - date = (int) time + " " - + context.getResources().getQuantityString(R.plurals.hour_plurals, (int) time); - if (time < 1) { - time = (double) (nowDate - pubDate.getTime()) / (1000 * 60); - date = (int) time + " " - + context.getResources().getQuantityString(R.plurals.min_plurals, (int) time); - if (time < 1) { - time = (double) (nowDate - pubDate.getTime()) / (1000); - date = (int) time + " " - + context.getResources().getQuantityString(R.plurals.sec_plurals, (int) time); - } - } - } - return date; - } - - public boolean isEqual(NewsRssItem item) { - return (item.getTitle().equals(title) && item.getSite().getName().equals(site.getName())); - } - - public Date getDate() { - return pubDate; - } - - public String getUrlImage() { - return urlImage; - } - - public static ArrayList getNews() { - return news; - } - - public static ArrayList getLikedNews() { - return likedNews; - } - - public Site getSite() { - return site; - } - - public HashSet getCategoryWords() { - return categoryWords; - } - - public String getLink() { - return link; - } - - public String getTitle() { - return title; - } -} diff --git a/app/src/main/java/com/example/project_28_02_2021/RssParser.java b/app/src/main/java/com/example/project_28_02_2021/RssParser.java deleted file mode 100644 index b2cd588..0000000 --- a/app/src/main/java/com/example/project_28_02_2021/RssParser.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.example.project_28_02_2021; - -import android.content.Context; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.parser.Parser; -import org.jsoup.select.Elements; - -import java.io.InputStream; -import java.util.Scanner; - -class RssParser extends Thread { - private final Site site; - private final Context context; - - public RssParser(Site site, Context context) { - this.site = site; - this.context = context; - } - - @Override - public void run() { - Thread loadThread = new Thread() { - @Override - public void run() { - try { - String xmlString = Jsoup.connect(site.getUrl()).get().toString(); - Document doc = Jsoup.parse(xmlString, "", Parser.xmlParser()); - context.openFileOutput("read.xml", Context.MODE_APPEND); - InputStream stream = context.openFileInput("read.xml"); - StringBuilder gotXml = new StringBuilder(); - Scanner scanner = new Scanner(stream); - while (scanner.hasNext()) { - gotXml.append(scanner.next()); - } - Document readDoc = Jsoup.parse(gotXml.toString(), "", Parser.xmlParser()); - site.setImageLink(doc.select("image").select("url").text()); - for (Element item : doc.select("item")) { - NewsRssItem newsRssItem = new NewsRssItem( - site, item.select("link").text(), - item.select("title").text(), - item.select("category").text().toLowerCase() + " " + item.select("description").text().toLowerCase() + " " + site.getName().toLowerCase(), - item.select("pubDate").text(), - doc.select("url").text(), - context); - boolean notRead = true; - Elements items = readDoc.select("item"); - for (Element elem : items) { - if (elem.select("title").text().equalsIgnoreCase(newsRssItem.getTitle().replace(" ", ""))) { - notRead = false; - } - } - boolean notAgain = true; - for (NewsRssItem rssItem : NewsRssItem.getNews()) { - if (rssItem.getTitle().equals(newsRssItem.getTitle())) { - notAgain = false; - break; - } - } - if (notRead && notAgain) { - NewsRssItem.getNews().add(newsRssItem); - } - } - } catch (Exception ignored) { - } - site.setStatus(Site.SiteStatusStates.FILLED_STATE); - } - }; - loadThread.run(); - } -} diff --git a/app/src/main/java/com/example/project_28_02_2021/SendingWorker.java b/app/src/main/java/com/example/project_28_02_2021/SendingWorker.java deleted file mode 100644 index 7fed2c1..0000000 --- a/app/src/main/java/com/example/project_28_02_2021/SendingWorker.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.example.project_28_02_2021; - -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.res.AssetManager; -import android.net.Uri; -import android.os.Build; -import android.util.Log; - -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; -import androidx.work.ForegroundInfo; -import androidx.work.Worker; -import androidx.work.WorkerParameters; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.parser.Parser; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Scanner; - -public class SendingWorker extends Worker { - - public SendingWorker(Context context, WorkerParameters workerParams) { - super(context, workerParams); - } - - @Override - public Result doWork() { - AssetManager assetManager = getApplicationContext().getAssets(); - ArrayList exe_rows = new ArrayList<>(); - try (InputStream inputStream = assetManager.open("sites_table.sql")) { - Scanner scanner = new Scanner(inputStream); - while (scanner.hasNext()) { - exe_rows.add(scanner.nextLine()); - } - } catch (IOException ignored) { - } - assetManager.close(); - Log.println(Log.ASSERT, "MSG", exe_rows.toString()); - DataBaseHelper dataBaseHelper = new DataBaseHelper(getApplicationContext(), new ArrayList<>()); - dataBaseHelper.getReadableDatabase(); - try { - Thread.sleep(4000); - } catch (Exception ignored) { - } - Log.println(Log.ASSERT, "MSG", dataBaseHelper.getSites().toString()); - ArrayList site_list = new ArrayList<>(dataBaseHelper.getSites()); - - Log.println(Log.ASSERT, "MSG", site_list.toString()); - ArrayList items = new ArrayList<>(); - - dataBaseHelper.close(); - - Thread loadThread = new Thread() { - @Override - public void run() { - try { - for (Site site : site_list) { - String xmlString = Jsoup.connect(site.getUrl()).get().toString(); - Document doc = Jsoup.parse(xmlString, "", Parser.xmlParser()); - for (Element item : doc.select("item")) { - NewsRssItem newsRssItem = new NewsRssItem( - site, item.select("link").text(), - item.select("title").text(), - item.select("category").text().toLowerCase() + " " + item.select("description").text().toLowerCase() + " " + site.getName().toLowerCase(), - item.select("pubDate").text(), - item.select("image").select("url").text(), - getApplicationContext()); - Log.println(Log.ASSERT, "MSG", newsRssItem.getTitle()); - items.add(newsRssItem); - } - } - } catch (Exception e) { - Log.println(Log.ASSERT, "MSG", e.getLocalizedMessage()); - } - } - }; - loadThread.start(); - try { - Thread.sleep(30000); - } catch (InterruptedException ignored) { - } - NotificationManagerCompat notificationManager = - NotificationManagerCompat.from(getApplicationContext()); - NotificationChannel channel = null; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - channel = new NotificationChannel("id", "Main_Thread", NotificationManager.IMPORTANCE_HIGH); - } - } - try { - if (channel != null) notificationManager.createNotificationChannel(channel); - } catch (Exception ignored) { - } - Log.println(Log.ASSERT, items.get(0).getTitle() == null ? "Null" : "MSG", "!!!"); - Intent shareIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(items.get(0).getLink())); - PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT); - NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), "id") - .setContentIntent(contentIntent) - .setSmallIcon(R.drawable.news_icon) - .setContentTitle("JavaNews") - .setContentText(items.get(0).getTitle()) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setAutoCancel(true); - Notification notification = builder.build(); - notification.defaults = Notification.DEFAULT_SOUND | - Notification.DEFAULT_VIBRATE; - int id = 0; - ForegroundInfo info = new ForegroundInfo(id, notification, 0); - setForegroundAsync(info); - notificationManager.notify(12, notification); - return Result.success(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/Site.java b/app/src/main/java/com/example/project_28_02_2021/Site.java deleted file mode 100644 index db8f74e..0000000 --- a/app/src/main/java/com/example/project_28_02_2021/Site.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.example.project_28_02_2021; - -import android.content.Context; - -import java.util.ArrayList; - -public class Site { - private static final ArrayList sites = new ArrayList<>(); - private final String name; - private final String url; - private String imageLink = ""; - private SiteStatusStates status = SiteStatusStates.UNFILLED_STATE; - private final Context context; - - public Site(String name, String url, Context context) { - this.name = name; - this.url = url; - this.context = context; - } - - public enum SiteStatusStates { - FILLED_STATE, - UNFILLED_STATE, - UNKNOWN_STATE, - } - - public static class SiteFactory { - public static Site getSiteByName(String name, Context context) { - for (Site site : sites) { - if (site.name.equals(name)) { - return site; - } - } - return new Site(name, "?", context); - } - } - - public String asString() { - return context.getString(R.string.str_site_data, name, url) - .replaceAll(".xml", "") - .replaceAll("://", "") - .replaceAll("https", "") - .replaceAll("http", "") - .replaceAll("ftp", "") - .replaceAll("ftps", ""); - } - - public int getItemsCount() { - int newsCount = 0; - for (NewsRssItem item : NewsRssItem.getNews()) { - if (item.getSite() == this) { - newsCount++; - } - } - return newsCount; - } - - public static ArrayList getSites() { - return sites; - } - - public void setStatus(SiteStatusStates status) { - this.status = status; - } - - public String getName() { - return name; - } - - public String getUrl() { - return url; - } - - public void setImageLink(String imageLink) { - this.imageLink = imageLink; - } - - public String getImageLink() { - return imageLink; - } - - public SiteStatusStates getStatus() { - return status; - } -} diff --git a/app/src/main/java/com/example/project_28_02_2021/SplashActivity.java b/app/src/main/java/com/example/project_28_02_2021/SplashActivity.java deleted file mode 100644 index e7de66f..0000000 --- a/app/src/main/java/com/example/project_28_02_2021/SplashActivity.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.example.project_28_02_2021; - -import android.content.Intent; -import android.content.res.AssetManager; -import android.os.Bundle; -import android.widget.ProgressBar; - -import androidx.appcompat.app.AppCompatActivity; -import androidx.work.ExistingPeriodicWorkPolicy; -import androidx.work.PeriodicWorkRequest; -import androidx.work.WorkManager; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Objects; -import java.util.Scanner; -import java.util.concurrent.TimeUnit; - -public class SplashActivity extends AppCompatActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(R.style.Custom_theme); - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_splash); - PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(SendingWorker.class, 15, TimeUnit.MINUTES). - setInitialDelay(15, TimeUnit.MINUTES).build(); - WorkManager.getInstance(this).enqueueUniquePeriodicWork("id", ExistingPeriodicWorkPolicy.REPLACE, request); - PreferenceManager manager = new PreferenceManager(this); - manager.setValueByKey( - new PreferenceManager.PreferencePair(PreferenceManager.FILTER_KEY, PreferenceManager.NONE_FILTER_MODE) - ); - Objects.requireNonNull(getSupportActionBar()).hide(); - AssetManager assetManager = getAssets(); - ArrayList exe_rows = new ArrayList<>(); - try (InputStream inputStream = assetManager.open("sites_table.sql")) { - Scanner scanner = new Scanner(inputStream); - while (scanner.hasNext()) { - exe_rows.add(scanner.nextLine()); - } - } catch (IOException ignored) { - } - DataBaseHelper dataBaseHelper = new DataBaseHelper(getApplicationContext(), exe_rows); - dataBaseHelper.getReadableDatabase(); - Site.getSites().addAll(dataBaseHelper.getSites()); - ProgressBar bar = findViewById(R.id.progress_bar); - Thread netThread = new Thread() { - - @Override - public void run() { - bar.post(() -> bar.setMax(Site.getSites().size())); - for (Site site : Site.getSites()) { - RssParser parser = new RssParser(site, getApplicationContext()); - parser.start(); - try { - while (site.getStatus() == Site.SiteStatusStates.UNFILLED_STATE) { - Thread.sleep(100); - } - } catch (InterruptedException ignored) { - site.setStatus(Site.SiteStatusStates.UNKNOWN_STATE); - } - bar.post(() -> bar.incrementProgressBy(1)); - } - Intent intent = new Intent(getApplicationContext(), MainActivity.class); - startActivity(intent); - } - }; - - netThread.start(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/activity/LikedNewsActivity.java b/app/src/main/java/com/example/project_28_02_2021/activity/LikedNewsActivity.java new file mode 100644 index 0000000..a1ad579 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/activity/LikedNewsActivity.java @@ -0,0 +1,110 @@ +package com.example.project_28_02_2021.activity; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +import com.example.project_28_02_2021.rss.adapter.NewsRssItemAdapter; +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.util.files.FileManager; +import com.example.project_28_02_2021.rss.ItemComparators; +import com.example.project_28_02_2021.rss.NewsRssItem; +import com.example.project_28_02_2021.rss.NewsRssItemManager; +import com.example.project_28_02_2021.util.settings.PreferenceManager; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Objects; + +public class LikedNewsActivity extends AppCompatActivity { + + private ListView listView = null; + private final NewsRssItemManager manager = NewsRssItemManager.getInstance(); + + private final AdapterView.OnItemClickListener itemListener = (parent, view, position, id) -> { + Uri uri = Uri.parse(manager.getLikedNews().get(position - 1).getLink()); + Intent web_intent = new Intent(Intent.ACTION_VIEW, uri); + startActivity(web_intent); + }; + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.delete_liked_list_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.delete_all) { + manager.clearLikedNews(); + NewsRssItemAdapter adapter = + new NewsRssItemAdapter(this, + R.layout.list_item_layout, + manager.getLikedNews(), + false); + listView.setAdapter(adapter); + findViewById(R.id.empty_view).setVisibility(View.VISIBLE); + FileManager.deleteFile(this, FileManager.liked_news_storage); + return true; + } else return super.onOptionsItemSelected(item); + } + + + public void setDefaultSettings() { + TextView emptyView = findViewById(R.id.empty_view); + listView.setEmptyView(emptyView); + if (manager.getLikedNews().isEmpty()) + return; + listView.setOnItemClickListener(itemListener); + Comparator defaultComparator; + PreferenceManager manager = new PreferenceManager(this); + switch (manager.getString(PreferenceManager.SORT_KEY, PreferenceManager.SORT_BY_DATE, this)) { + case PreferenceManager.SORT_BY_DATE: + defaultComparator = NewsRssItemManager.getComparator(ItemComparators.SORT_BY_DATE); + break; + case PreferenceManager.SORT_BY_SITE: + defaultComparator = NewsRssItemManager.getComparator(ItemComparators.SORT_BY_SITE); + break; + case PreferenceManager.SORT_BY_SIZE: + defaultComparator = NewsRssItemManager.getComparator(ItemComparators.SORT_BY_SIZE); + break; + default: + defaultComparator = (n_1, n_2) -> 0; + } + Collections.sort(this.manager.getLikedNews(), defaultComparator); + View footer = LayoutInflater.from(this).inflate(R.layout.favorites_footer, listView, false); + View.OnClickListener footer_listener = (v) -> listView.smoothScrollToPosition(0); + footer.setOnClickListener(footer_listener); + listView.setFooterDividersEnabled(true); + listView.addFooterView(footer); + View header = LayoutInflater.from(this).inflate(R.layout.favorites_header, listView, false); + View.OnClickListener header_listener = (v) -> listView.smoothScrollToPosition(listView.getAdapter().getCount() - 1); + header.setOnClickListener(header_listener); + listView.setHeaderDividersEnabled(true); + listView.addHeaderView(header); + NewsRssItemAdapter adapter = + new NewsRssItemAdapter(this, + R.layout.list_item_layout, + this.manager.getLikedNews(), + false); + listView.setAdapter(adapter); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_favorites); + Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + listView = findViewById(R.id.liked_news_list); + setDefaultSettings(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/MainActivity.java b/app/src/main/java/com/example/project_28_02_2021/activity/MainActivity.java similarity index 75% rename from app/src/main/java/com/example/project_28_02_2021/MainActivity.java rename to app/src/main/java/com/example/project_28_02_2021/activity/MainActivity.java index 6bb0732..cd22f2a 100644 --- a/app/src/main/java/com/example/project_28_02_2021/MainActivity.java +++ b/app/src/main/java/com/example/project_28_02_2021/activity/MainActivity.java @@ -1,4 +1,4 @@ -package com.example.project_28_02_2021; +package com.example.project_28_02_2021.activity; import android.content.Intent; import android.content.SharedPreferences; @@ -8,6 +8,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Looper; +import android.util.Log; import android.util.Patterns; import android.view.Menu; import android.view.MenuItem; @@ -24,6 +25,19 @@ import androidx.work.PeriodicWorkRequest; import androidx.work.WorkManager; +import com.example.project_28_02_2021.notification.ConnectionWorker; +import com.example.project_28_02_2021.rss.adapter.NewsRssItemAdapter; +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.rss.ItemComparators; +import com.example.project_28_02_2021.rss.NewsRssItem; +import com.example.project_28_02_2021.rss.NewsRssItemManager; +import com.example.project_28_02_2021.site.Site; +import com.example.project_28_02_2021.site.SiteManager; +import com.example.project_28_02_2021.site.SiteStatusStates; +import com.example.project_28_02_2021.util.database.DataBaseHelper; +import com.example.project_28_02_2021.util.settings.PreferenceManager; +import com.example.project_28_02_2021.notification.SendingWorker; +import com.example.project_28_02_2021.util.net.NetLoader; import com.google.android.material.snackbar.Snackbar; import org.jsoup.Jsoup; @@ -49,9 +63,10 @@ public class MainActivity extends AppCompatActivity { private ListView listView = null; private SwipeRefreshLayout refreshLayout = null; private Comparator defaultComparator = null; - private AdapterView.OnItemClickListener itemListener = (parent, view, position, id) -> { - }; + private AdapterView.OnItemClickListener itemListener = (parent, view, position, id) -> { }; private static boolean created = false; + private final NewsRssItemManager n_manager = NewsRssItemManager.getInstance(); + private final SiteManager s_manager = SiteManager.getInstance(this, new ArrayList<>()); private void setDefaultSettings() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { @@ -73,41 +88,47 @@ private void setDefaultSettings() { if (!adapter.isEmpty()) { adapter.clear(); } - if (!Site.getSites().isEmpty()) { - Site.getSites().clear(); + if (!s_manager.getSites().isEmpty()) { + s_manager.getSites().clear(); } - if (!NewsRssItem.getNews().isEmpty()) { - NewsRssItem.getNews().clear(); + if (!n_manager.getNews().isEmpty()) { + n_manager.getNews().clear(); } dataBaseHelper.getReadableDatabase(); - Site.getSites().addAll(dataBaseHelper.getSites()); - for (Site site : Site.getSites()) { - RssParser parser = new RssParser(site, this); - parser.start(); + s_manager.getSites().addAll(dataBaseHelper.getSites()); + for (Site site : s_manager.getSites()) { + NetLoader.loadFromSite(this, site); try { - while (site.getStatus() == Site.SiteStatusStates.UNFILLED_STATE) { + while (site.getStatus() == SiteStatusStates.UNFILLED_STATE) { Thread.sleep(100); } } catch (InterruptedException ignored) { - site.setStatus(Site.SiteStatusStates.UNKNOWN_STATE); + site.setStatus(SiteStatusStates.UNKNOWN_STATE); } } - if (NewsRssItem.getNews().isEmpty()) { + if (n_manager.getNews().isEmpty()) { Snackbar.make(listView, getString(R.string.str_net_exception), Snackbar.LENGTH_LONG).show(); + Log.d("!!!", "OK"); + PeriodicWorkRequest request + = new PeriodicWorkRequest.Builder(ConnectionWorker.class, + ConnectionWorker.interval_min, + ConnectionWorker.time_unit).build(); + WorkManager manager = WorkManager.getInstance(getApplicationContext()); + manager.enqueueUniquePeriodicWork(ConnectionWorker.work_id, ExistingPeriodicWorkPolicy.KEEP, request); } else { - String message = getString(R.string.str_upload_news_data, NewsRssItem.getNews().size(), - getApplicationContext().getResources().getQuantityString(R.plurals.items_plurals, NewsRssItem.getNews().size()), - Site.getSites().size(), - getResources().getQuantityString(R.plurals.sites_plurals, Site.getSites().size()) + String message = getString(R.string.str_upload_news_data, n_manager.getNews().size(), + getApplicationContext().getResources().getQuantityString(R.plurals.items_plurals, n_manager.getNews().size()), + s_manager.getSites().size(), + getResources().getQuantityString(R.plurals.sites_plurals, s_manager.getSites().size()) ); Snackbar.make(listView, message, Snackbar.LENGTH_LONG).show(); } - Collections.sort(NewsRssItem.getNews(), defaultComparator); + Collections.sort(n_manager.getNews(), defaultComparator); setDefaultSettings(); listView.post(() -> adapter.notifyDataSetChanged()); itemListener = (parent, view, position, id) -> startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse(NewsRssItem.getNews().get(position).getLink()))); + Uri.parse(n_manager.getNews().get(position).getLink()))); listView.post(() -> { listView.setOnItemClickListener(itemListener); setTitle(R.string.app_name); @@ -120,22 +141,22 @@ private void setDefaultSettings() { refreshLayout.setOnRefreshListener(listener); switch (settings.getString(PreferenceManager.SORT_KEY, PreferenceManager.SORT_BY_DATE)) { case PreferenceManager.SORT_BY_DATE: - defaultComparator = NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_DATE); + defaultComparator = NewsRssItemManager.getComparator(ItemComparators.SORT_BY_DATE); break; case PreferenceManager.SORT_BY_SITE: - defaultComparator = NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_SITE); + defaultComparator = NewsRssItemManager.getComparator(ItemComparators.SORT_BY_SITE); break; case PreferenceManager.SORT_BY_SIZE: - defaultComparator = NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_SIZE); + defaultComparator = NewsRssItemManager.getComparator(ItemComparators.SORT_BY_SIZE); break; } - Collections.sort(NewsRssItem.getNews(), defaultComparator); + Collections.sort(n_manager.getNews(), defaultComparator); if (settings.getString(PreferenceManager.FILTER_KEY, PreferenceManager.NONE_FILTER_MODE).equals(PreferenceManager.NONE_FILTER_MODE)) { - adapter = new NewsRssItemAdapter(this, R.layout.list_item_layout, NewsRssItem.getNews(), true); + adapter = new NewsRssItemAdapter(this, R.layout.list_item_layout, n_manager.getNews(), true); listView.post(() -> listView.setAdapter(adapter)); itemListener = (parent, view, position, id) -> startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse(NewsRssItem.getNews().get(position).getLink()))); + Uri.parse(n_manager.getNews().get(position).getLink()))); } else { String[] tags = null; try { @@ -155,7 +176,7 @@ private void setDefaultSettings() { assert tags != null; ArrayList filteredNews = new ArrayList<>(); - for (NewsRssItem item : NewsRssItem.getNews()) { + for (NewsRssItem item : n_manager.getNews()) { for (String tag : tags) { String lower_tag = tag.toLowerCase().trim(); if (item.getCategoryWords().contains(lower_tag)) { @@ -259,15 +280,11 @@ protected void onCreate(Bundle savedInstanceState) { ); } - PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(SendingWorker.class, 15, TimeUnit.MINUTES). - setInitialDelay(15, TimeUnit.MINUTES).build(); - WorkManager.getInstance(this).enqueueUniquePeriodicWork("id_work", ExistingPeriodicWorkPolicy.REPLACE, request); - listView = findViewById(R.id.list_view); refreshLayout = findViewById(R.id.swipe); AssetManager assetManager = getAssets(); ArrayList exe_rows = new ArrayList<>(); - try (InputStream inputStream = assetManager.open("sites_table.sql")) { + try (InputStream inputStream = getAssets().open("sites_table.sql")) { Scanner scanner = new Scanner(inputStream); while (scanner.hasNext()) { exe_rows.add(scanner.nextLine()); @@ -278,21 +295,28 @@ protected void onCreate(Bundle savedInstanceState) { registerForContextMenu(listView); setDefaultSettings(); if (!created) { - if (NewsRssItem.getNews().isEmpty()) { + if (n_manager.getNews().isEmpty()) { Snackbar.make(listView, getString(R.string.str_net_exception), Snackbar.LENGTH_LONG).show(); + PeriodicWorkRequest request + = new PeriodicWorkRequest.Builder(ConnectionWorker.class, + ConnectionWorker.interval_min, + ConnectionWorker.time_unit).build(); + WorkManager manager = WorkManager.getInstance(getApplicationContext()); + manager.enqueueUniquePeriodicWork(ConnectionWorker.work_id, ExistingPeriodicWorkPolicy.KEEP, request); + } else { - String message = getString(R.string.str_upload_news_data, NewsRssItem.getNews().size(), - getApplicationContext().getResources().getQuantityString(R.plurals.items_plurals, NewsRssItem.getNews().size()), - Site.getSites().size(), - getResources().getQuantityString(R.plurals.sites_plurals, Site.getSites().size()) + String message = getString(R.string.str_upload_news_data, n_manager.getNews().size(), + getApplicationContext().getResources().getQuantityString(R.plurals.items_plurals, n_manager.getNews().size()), + s_manager.getSites().size(), + getResources().getQuantityString(R.plurals.sites_plurals, s_manager.getSites().size()) ); Snackbar.make(listView, message, Snackbar.LENGTH_LONG).show(); } - Collections.sort(NewsRssItem.getNews(), defaultComparator); + Collections.sort(n_manager.getNews(), defaultComparator); created = true; } - NewsRssItem.getLikedNews().clear(); + n_manager.getLikedNews().clear(); StringBuilder xmlString = new StringBuilder(); try (InputStream inputStream = openFileInput("news.xml")) { Scanner scanner = new Scanner(inputStream); @@ -305,19 +329,19 @@ protected void onCreate(Bundle savedInstanceState) { Elements news = doc.select("item"); for (org.jsoup.nodes.Element item : news) { NewsRssItem newsRssItem = new NewsRssItem( - Site.SiteFactory.getSiteByName(item.select("site").text(), this), + s_manager.getSiteByName(item.select("site").text(), this), item.select("link").text(), item.select("title").text(), "", item.select("pubDate").text(), - item.select("image").text(), this); + this); boolean notAgain = true; - for (NewsRssItem it : NewsRssItem.getLikedNews()) { + for (NewsRssItem it : n_manager.getLikedNews()) { if (it.isEqual(newsRssItem)) { notAgain = false; break; } } if (notAgain) { - NewsRssItem.getLikedNews().add(newsRssItem); + n_manager.getLikedNews().add(newsRssItem); } } } diff --git a/app/src/main/java/com/example/project_28_02_2021/SettingsActivity.java b/app/src/main/java/com/example/project_28_02_2021/activity/SettingsActivity.java similarity index 70% rename from app/src/main/java/com/example/project_28_02_2021/SettingsActivity.java rename to app/src/main/java/com/example/project_28_02_2021/activity/SettingsActivity.java index d3b20d8..8b9d4f4 100644 --- a/app/src/main/java/com/example/project_28_02_2021/SettingsActivity.java +++ b/app/src/main/java/com/example/project_28_02_2021/activity/SettingsActivity.java @@ -1,6 +1,8 @@ -package com.example.project_28_02_2021; +package com.example.project_28_02_2021.activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; import android.text.Editable; @@ -12,12 +14,22 @@ import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.rss.ItemComparators; +import com.example.project_28_02_2021.rss.NewsRssItemManager; +import com.example.project_28_02_2021.site.Site; +import com.example.project_28_02_2021.site.SiteManager; +import com.example.project_28_02_2021.site.adapter.SiteAdapter; +import com.example.project_28_02_2021.util.files.FileManager; +import com.example.project_28_02_2021.util.settings.PreferenceManager; + import org.jsoup.Jsoup; import org.jsoup.parser.Parser; import org.w3c.dom.Document; import org.w3c.dom.Element; import java.io.InputStream; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -30,7 +42,7 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import static com.example.project_28_02_2021.PreferenceManager.SORT_BY_DATE; +import static com.example.project_28_02_2021.util.settings.PreferenceManager.SORT_BY_DATE; public class SettingsActivity extends AppCompatActivity { @@ -57,9 +69,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); ActionBar bar = getSupportActionBar(); - if (bar != null) { - bar.setDisplayHomeAsUpEnabled(true); - } + if (bar != null) { bar.setDisplayHomeAsUpEnabled(true); } SharedPreferences settings = getSharedPreferences(PreferenceManager.SETTINGS_NAME, MODE_MULTI_PROCESS); SharedPreferences.Editor editor = settings.edit(); RadioGroup sortGroup = findViewById(R.id.sort_list); @@ -77,24 +87,25 @@ protected void onCreate(Bundle savedInstanceState) { (group, checkedId) -> { PreferenceManager manager = new PreferenceManager(this); + NewsRssItemManager news_manager = NewsRssItemManager.getInstance(); if (checkedId == R.id.sort_by_date_button) { manager.setValueByKey( new PreferenceManager.PreferencePair(PreferenceManager.SORT_KEY, PreferenceManager.SORT_BY_DATE) ); - Collections.sort(NewsRssItem.getNews(), - NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_DATE)); + Collections.sort(news_manager.getNews(), + NewsRssItemManager.getComparator(ItemComparators.SORT_BY_DATE)); } else if (checkedId == R.id.sort_by_site_button) { manager.setValueByKey( new PreferenceManager.PreferencePair(PreferenceManager.SORT_KEY, PreferenceManager.SORT_BY_SITE) ); - Collections.sort(NewsRssItem.getNews(), - NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_SITE)); + Collections.sort(news_manager.getNews(), + NewsRssItemManager.getComparator(ItemComparators.SORT_BY_SITE)); } else if (checkedId == R.id.sort_by_size_button) { manager.setValueByKey( new PreferenceManager.PreferencePair(PreferenceManager.SORT_KEY, PreferenceManager.SORT_BY_SIZE) ); - Collections.sort(NewsRssItem.getNews(), - NewsRssItem.getComparator(NewsRssItem.ItemComparators.SORT_BY_SIZE)); + Collections.sort(news_manager.getNews(), + NewsRssItemManager.getComparator(ItemComparators.SORT_BY_SIZE)); } editor.apply(); }; @@ -112,7 +123,31 @@ protected void onCreate(Bundle savedInstanceState) { modeGroup.setOnCheckedChangeListener(modeChangeListener); editor.commit(); ListView sitesList = findViewById(R.id.site_settings_list); - SiteAdapter adapter = new SiteAdapter(this, R.layout.list_site_layout, Site.getSites()); + sitesList.setEmptyView(findViewById(R.id.empty)); + sitesList.setOnItemClickListener((parent, view, position, id) -> { + SiteManager manager = SiteManager.getInstance(this, new ArrayList<>()); + Site item = manager.getSites().get(position); + final DialogInterface.OnClickListener pos_listener = (pos_dialog, which) -> { + manager.deleteSite(item); + SiteAdapter adapter = new SiteAdapter( + this, + R.layout.list_site_layout, + manager.getSites() + ); + sitesList.setAdapter(adapter); + }; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + AlertDialog dialog = builder + .setTitle(R.string.str_delete_full_site) + .setMessage(getString(R.string.str_sure, item.getName())) + .setPositiveButton(R.string.str_delete_site, pos_listener) + .setNegativeButton(R.string.str_add_site_neg_button, (neg_dialog, which) -> {} ) + .create(); + dialog.show(); + }); + SiteAdapter adapter = new SiteAdapter(this, + R.layout.list_site_layout, + SiteManager.getInstance(this, new ArrayList<>()).getSites()); sitesList.setAdapter(adapter); registerForContextMenu(sitesList); TextWatcher watcher = new TextWatcher() { @@ -129,8 +164,8 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void onTextChanged(CharSequence s, int start, int before, int count) { String[] tags = s.toString().split(","); try { - deleteFile("tags.xml"); - openFileOutput("tags.xml", MODE_APPEND); + deleteFile(FileManager.tags_storage); + openFileOutput(FileManager.tags_storage, MODE_APPEND); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.newDocument(); @@ -144,7 +179,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(document); - StreamResult result = new StreamResult(openFileOutput("tags.xml", Context.MODE_APPEND)); + StreamResult result = new StreamResult(openFileOutput(FileManager.tags_storage, Context.MODE_APPEND)); transformer.transform(source, result); PreferenceManager manager = new PreferenceManager(getApplicationContext()); manager.setValueByKey( @@ -156,10 +191,10 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { }; String last_data = " "; try { - openFileOutput("tags.xml", MODE_APPEND); + openFileOutput(FileManager.tags_storage, MODE_APPEND); } catch (Exception ignored) { } - try (InputStream in_stream = openFileInput("tags.xml")) { + try (InputStream in_stream = openFileInput(FileManager.tags_storage)) { StringBuilder tmp_str = new StringBuilder(); Scanner in_scan = new Scanner(in_stream); while (in_scan.hasNext()) { diff --git a/app/src/main/java/com/example/project_28_02_2021/activity/SplashActivity.java b/app/src/main/java/com/example/project_28_02_2021/activity/SplashActivity.java new file mode 100644 index 0000000..0cb7065 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/activity/SplashActivity.java @@ -0,0 +1,63 @@ +package com.example.project_28_02_2021.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.widget.ProgressBar; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; + +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.util.files.FileManager; +import com.example.project_28_02_2021.site.Site; +import com.example.project_28_02_2021.site.SiteManager; +import com.example.project_28_02_2021.site.SiteStatusStates; +import com.example.project_28_02_2021.util.settings.PreferenceManager; +import com.example.project_28_02_2021.notification.SendingWorker; +import com.example.project_28_02_2021.util.net.NetLoader; + +import java.util.ArrayList; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +public class SplashActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + setTheme(R.style.Custom_theme); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash); + Objects.requireNonNull(getSupportActionBar()).hide(); + PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(SendingWorker.class, SendingWorker.interval_min, TimeUnit.MINUTES) + .setInitialDelay(SendingWorker.interval_min, TimeUnit.MINUTES) + .build(); + WorkManager.getInstance(this).enqueueUniquePeriodicWork(SendingWorker.chn_id, ExistingPeriodicWorkPolicy.REPLACE, request); + PreferenceManager manager = new PreferenceManager(this); + manager.setValueByKey( + new PreferenceManager.PreferencePair(PreferenceManager.FILTER_KEY, PreferenceManager.NONE_FILTER_MODE) + ); + ArrayList exe_rows = new ArrayList<>(); + try { exe_rows = FileManager.getAssetData(getAssets());} + catch (Exception ignored) {} + ArrayList sites = SiteManager.getInstance(this, exe_rows).getSites(); + ProgressBar bar = findViewById(R.id.progress_bar); + Thread start_thread = new Thread() { + @Override public void run() { + bar.post( () -> bar.setMax(sites.size()) ); + for (Site site : sites) { + NetLoader.loadFromSite(getApplicationContext(), site); + try { while (site.getStatus() == SiteStatusStates.UNFILLED_STATE) Thread.sleep(100); } + catch (InterruptedException ignored) { site.setStatus(SiteStatusStates.UNKNOWN_STATE); } + bar.post(() -> bar.incrementProgressBy(1)); + } + Intent intent = new Intent(getApplicationContext(), MainActivity.class); + try { Thread.sleep(1000); } + catch (InterruptedException ignored) {} + startActivity(intent); + } + }; + start_thread.start(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/notification/ConnectionWorker.java b/app/src/main/java/com/example/project_28_02_2021/notification/ConnectionWorker.java new file mode 100644 index 0000000..c677cc8 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/notification/ConnectionWorker.java @@ -0,0 +1,114 @@ +package com.example.project_28_02_2021.notification; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.util.Log; + +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.ForegroundInfo; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.activity.SplashActivity; +import com.example.project_28_02_2021.notification.interfaces.ISend; +import com.example.project_28_02_2021.rss.NewsRssItem; +import com.example.project_28_02_2021.site.Site; +import com.example.project_28_02_2021.site.SiteManager; +import com.example.project_28_02_2021.util.xml.XmlFeedParser; + +import org.jsoup.Jsoup; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +public class ConnectionWorker extends Worker implements ISend { + + public ConnectionWorker(Context context, WorkerParameters workerParams) { super(context, workerParams); } + + public static String work_id = "work_id"; + public static int interval_min = 15; + public static TimeUnit time_unit = TimeUnit.MINUTES; + public static String chn_id = "id"; + public static String chn_name = "Main_Thread"; + private ArrayList items; + private final NotificationManagerCompat notificationManager + = NotificationManagerCompat.from(getApplicationContext()); + + private final Runnable check_connection = () -> { + ArrayList sites = SiteManager.getInstance(getApplicationContext(), new ArrayList<>()).getSites(); + for (Site site : sites) { + String xmlString = ""; + try { xmlString = Jsoup.connect(site.getUrl()).get().toString(); } + catch (Exception ignored) {} + items = XmlFeedParser.parseFeedFromXml(xmlString, site, getApplicationContext()); + } + }; + + @Override + public void createCurrentChannel() { + NotificationChannel channel = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + channel = new NotificationChannel(chn_id, chn_name, NotificationManager.IMPORTANCE_HIGH); + try { if (channel != null) notificationManager.createNotificationChannel(channel); + } catch (Exception ignored) {} + } + + public PendingIntent getContentIntent() { + Intent intent = new Intent(getApplicationContext(), SplashActivity.class); + return PendingIntent.getActivity( + getApplicationContext(), + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT + ); + } + + @Override + public Notification getNotification(PendingIntent contentIntent) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), chn_id) + .setContentIntent(contentIntent) + .setSmallIcon(R.drawable.news_icon) + .setContentText(getApplicationContext().getString(R.string.str_connection_revived)) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setAutoCancel(true); + return builder.build(); + } + + @Override + public void resetWork() { + PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(ConnectionWorker.class, interval_min, time_unit).build(); + WorkManager manager = WorkManager.getInstance(getApplicationContext()); + manager.enqueueUniquePeriodicWork(work_id, ExistingPeriodicWorkPolicy.REPLACE, request); + } + + @Override + public Result doWork() { + Thread check_thread = new Thread(check_connection); + check_thread.start(); + try { Thread.sleep(60 * 1000); } + catch (InterruptedException ignored) {} + boolean has_connection = !items.isEmpty(); + if (has_connection) { + createCurrentChannel(); + PendingIntent intent = getContentIntent(); + Notification notification = getNotification(intent); + notification.defaults = Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE; + ForegroundInfo info = new ForegroundInfo(0, notification, 0); + setForegroundAsync(info); + notificationManager.notify(12, notification); + return Result.success(); + } + resetWork(); + return Result.failure(); + } +} diff --git a/app/src/main/java/com/example/project_28_02_2021/notification/SendingWorker.java b/app/src/main/java/com/example/project_28_02_2021/notification/SendingWorker.java new file mode 100644 index 0000000..0bc6d00 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/notification/SendingWorker.java @@ -0,0 +1,116 @@ +package com.example.project_28_02_2021.notification; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; + +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.ForegroundInfo; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import com.example.project_28_02_2021.notification.interfaces.ISend; +import com.example.project_28_02_2021.rss.NewsRssItem; +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.site.Site; +import com.example.project_28_02_2021.site.SiteManager; +import com.example.project_28_02_2021.util.xml.XmlFeedParser; + +import org.jsoup.Jsoup; + +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +public class SendingWorker extends Worker implements ISend { + + public SendingWorker(Context context, WorkerParameters workerParams) { super(context, workerParams); } + + public static String work_id = "id_work"; + public static int interval_min = 15; + public static TimeUnit time_unit = TimeUnit.MINUTES; + public static String chn_id = "id"; + public static String chn_name = "Main_Thread"; + private ArrayList items; + private NotificationChannel channel; + private int pos; + private final NotificationManagerCompat notificationManager + = NotificationManagerCompat.from(getApplicationContext()); + + private final Runnable loader = () -> { + ArrayList sites = SiteManager.getInstance(getApplicationContext(), new ArrayList<>()).getSites(); + for (Site site : sites) { + String xmlString = ""; + try { xmlString = Jsoup.connect(site.getUrl()).get().toString(); } + catch (Exception ignored) {} + items = XmlFeedParser.parseFeedFromXml(xmlString, site, getApplicationContext()); + } + }; + + @Override + public void createCurrentChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + channel = new NotificationChannel(chn_id, chn_name, NotificationManager.IMPORTANCE_HIGH); + try { if (channel != null) notificationManager.createNotificationChannel(channel); + } catch (Exception ignored) {} + } + + private PendingIntent getContentIntent(int pos) { + Intent shareIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(items.get(pos).getLink())); + return PendingIntent.getActivity( + getApplicationContext(), + 0, + shareIntent, + PendingIntent.FLAG_UPDATE_CURRENT + ); + } + + @Override + public Notification getNotification(PendingIntent contentIntent) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), chn_id) + .setContentIntent(contentIntent) + .setSmallIcon(R.drawable.news_icon) + .setContentText(items.get(pos).getTitle()) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setAutoCancel(true); + return builder.build(); + } + + @Override + public void resetWork() { + PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(SendingWorker.class, interval_min, time_unit) + .setInitialDelay(interval_min, time_unit) + .build(); + WorkManager manager = WorkManager.getInstance(getApplicationContext()); + manager.enqueueUniquePeriodicWork(work_id, ExistingPeriodicWorkPolicy.KEEP, request); + } + + @Override + public Result doWork() { + Thread loadThread = new Thread(loader); + loadThread.start(); + try { Thread.sleep(60 * 1000); } + catch (InterruptedException ignored) {} + if (items.isEmpty()) return Result.failure(); + Random random = new Random(); + pos = random.nextInt(items.size()); + createCurrentChannel(); + PendingIntent contentIntent = getContentIntent(pos); + Notification notification = getNotification(contentIntent); + notification.defaults = Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE; + ForegroundInfo info = new ForegroundInfo(0, notification, 0); + setForegroundAsync(info); + notificationManager.notify(12, notification); + resetWork(); + return Result.success(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/notification/interfaces/ISend.java b/app/src/main/java/com/example/project_28_02_2021/notification/interfaces/ISend.java new file mode 100644 index 0000000..35d9b1a --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/notification/interfaces/ISend.java @@ -0,0 +1,10 @@ +package com.example.project_28_02_2021.notification.interfaces; + +import android.app.Notification; +import android.app.PendingIntent; + +public interface ISend { + void createCurrentChannel(); + Notification getNotification(PendingIntent intent); + void resetWork(); +} diff --git a/app/src/main/java/com/example/project_28_02_2021/rss/ItemComparators.java b/app/src/main/java/com/example/project_28_02_2021/rss/ItemComparators.java new file mode 100644 index 0000000..50a7504 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/rss/ItemComparators.java @@ -0,0 +1,7 @@ +package com.example.project_28_02_2021.rss; + +public enum ItemComparators { + SORT_BY_SIZE, + SORT_BY_SITE, + SORT_BY_DATE, +} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/rss/NewsRssItem.java b/app/src/main/java/com/example/project_28_02_2021/rss/NewsRssItem.java new file mode 100644 index 0000000..83eb345 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/rss/NewsRssItem.java @@ -0,0 +1,95 @@ +package com.example.project_28_02_2021.rss; + +import android.content.Context; + +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.site.Site; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Locale; + +public class NewsRssItem implements Comparable { + private final Site site; + private final String link; + private final String title; + private final HashSet categoryWords = new HashSet<>(); + private final Context context; + private Date pubDate; + + public NewsRssItem(Site site, + String link, + String title, + String categoryData, + String pubDate, + Context context) { + this.site = site; + this.link = link; + this.title = title; + this.context = context; + + String letters = ",.:-[{}]&*@!?;\"'#$%^()+-=><|\\/~`"; + StringBuilder builder = new StringBuilder(); + char[] chars = categoryData.concat(title.toLowerCase()).trim().toCharArray(); + for (char letter : chars) { + if (letter == ' ') { + categoryWords.add(builder.toString().trim()); + builder = new StringBuilder(); + } else { + boolean isValid = true; + for (char ch : letters.toCharArray()) + if (ch == letter) { + isValid = false; + break; + } + if (!isValid) + continue; + } + builder.append(letter); + } + + categoryWords.add(builder.toString().trim()); + categoryWords.add(site.getName().trim().toLowerCase()); + String[] patterns = new String[]{ "E, d MMM yyyy H:m:s z", "E MMM dd HH:mm:ss z yyyy" }; + this.pubDate = new Date(System.currentTimeMillis()); + for (String pattern : patterns) { + try { this.pubDate = new SimpleDateFormat(pattern, Locale.US).parse(pubDate); } + catch (ParseException ignored) {} + } + } + + public String getRegexDate() { + long nowDate = Calendar.getInstance().getTimeInMillis(); + double time = (double) (nowDate - pubDate.getTime()) / (1000 * 60 * 60 * 24); + String date = (int) time + " " + + context.getResources().getQuantityString(R.plurals.day_plurals, (int) time); + if (time < 1) { + time = (double) (nowDate - pubDate.getTime()) / (1000 * 60 * 60); + date = (int) time + " " + + context.getResources().getQuantityString(R.plurals.hour_plurals, (int) time); + if (time < 1) { + time = (double) (nowDate - pubDate.getTime()) / (1000 * 60); + date = (int) time + " " + + context.getResources().getQuantityString(R.plurals.min_plurals, (int) time); + if (time < 1) { + time = (double) (nowDate - pubDate.getTime()) / (1000); + date = (int) time + " " + + context.getResources().getQuantityString(R.plurals.sec_plurals, (int) time); + } + } + } + return date; + } + + @Override + public int compareTo(NewsRssItem n) { return n.title.compareToIgnoreCase(title); } + public boolean isEqual(NewsRssItem n) { return title.equalsIgnoreCase(n.title); } + public Date getDate() { return pubDate; } + public Site getSite() { return site; } + public HashSet getCategoryWords() { return categoryWords; } + public String getLink() { return link; } + public String getTitle() { return title; } +} diff --git a/app/src/main/java/com/example/project_28_02_2021/rss/NewsRssItemManager.java b/app/src/main/java/com/example/project_28_02_2021/rss/NewsRssItemManager.java new file mode 100644 index 0000000..965f497 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/rss/NewsRssItemManager.java @@ -0,0 +1,43 @@ +package com.example.project_28_02_2021.rss; + +import java.util.ArrayList; +import java.util.Comparator; + +public class NewsRssItemManager { + + private static final ArrayList news = new ArrayList<>(); + private static final ArrayList likedNews = new ArrayList<>(); + private static NewsRssItemManager manager = null; + + public static NewsRssItemManager getInstance() { + if (manager == null) { manager = new NewsRssItemManager(); } + return manager; + } + + public static Comparator getComparator(ItemComparators type) { + Comparator itemComparator = (n_1, n_2) -> 0; + switch (type) { + case SORT_BY_SIZE: + itemComparator = (n_1, n_2) -> + Integer.compare(n_2.getTitle().length(), n_1.getTitle().length()); + break; + case SORT_BY_SITE: + itemComparator = (n_1, n_2) -> + n_1.getSite().getName().compareToIgnoreCase(n_2.getSite().getName()); + break; + case SORT_BY_DATE: + itemComparator = (n_1, n_2) -> + n_2.getDate().compareTo(n_1.getDate()); + break; + } + return itemComparator; + } + + private NewsRssItemManager() {} + public void clearNews() { news.clear(); } + public void clearLikedNews() { likedNews.clear(); } + public ArrayList getNews() { return news; } + public ArrayList getLikedNews() { return likedNews; } + public void addNews(NewsRssItem item) { news.add(item); } + public void addLikedNews(NewsRssItem item) { likedNews.add(item); } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/NewsRssItemAdapter.java b/app/src/main/java/com/example/project_28_02_2021/rss/adapter/NewsRssItemAdapter.java similarity index 85% rename from app/src/main/java/com/example/project_28_02_2021/NewsRssItemAdapter.java rename to app/src/main/java/com/example/project_28_02_2021/rss/adapter/NewsRssItemAdapter.java index e316c85..6c9f258 100644 --- a/app/src/main/java/com/example/project_28_02_2021/NewsRssItemAdapter.java +++ b/app/src/main/java/com/example/project_28_02_2021/rss/adapter/NewsRssItemAdapter.java @@ -1,4 +1,4 @@ -package com.example.project_28_02_2021; +package com.example.project_28_02_2021.rss.adapter; import android.content.Context; import android.content.Intent; @@ -11,6 +11,9 @@ import androidx.appcompat.app.AlertDialog; +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.rss.NewsRssItem; +import com.example.project_28_02_2021.rss.NewsRssItemManager; import com.google.android.material.snackbar.Snackbar; import org.jsoup.Jsoup; @@ -51,7 +54,6 @@ private static class ViewHolder { final TextView textView; final TextView dateView; final ImageView share, delete, like; - // final ImageView image; public ViewHolder(View view) { textView = view.findViewById(R.id.item_text_view); @@ -59,7 +61,6 @@ public ViewHolder(View view) { share = view.findViewById(R.id.share_button); delete = view.findViewById(R.id.delete_button); like = view.findViewById(R.id.like_button); - // image = view.findViewById(R.id.image_icon); } } @@ -70,32 +71,18 @@ public View getView(int pos, View convertView, ViewGroup parents) { convertView = inflater.inflate(layoutRes, parents, false); viewHolder = new ViewHolder(convertView); convertView.setTag(viewHolder); - } else { - viewHolder = (ViewHolder) convertView.getTag(); - } + } else { viewHolder = (ViewHolder) convertView.getTag(); } NewsRssItem item = items.get(pos); - /* - getContext().getAssets(); - viewHolder.image.setImageResource(R.drawable.news_icon); - try { Picasso.with(getContext()).load(item.getUrlImage()) - .error(R.drawable.news_icon) - .into(viewHolder.image); - } catch (Exception e) { - viewHolder.image.setImageResource(R.drawable.news_icon); } - */ boolean liked = false; - for (NewsRssItem likedItem : NewsRssItem.getLikedNews()) { - if (likedItem.isEqual(item)) { + for (NewsRssItem likedItem : NewsRssItemManager.getInstance().getLikedNews()) + if (likedItem.compareTo(item) == 0) liked = true; - } - } - if (liked) { - viewHolder.like.setColorFilter(R.color.black); - } else { - viewHolder.like.clearColorFilter(); - } + if (liked) { viewHolder.like.setColorFilter(R.color.black); } + else { viewHolder.like.clearColorFilter(); } viewHolder.textView.setText(getContext().getString(R.string.str_adapter_add_data, - item.getTitle(), item.getSite().getName())); + item.getTitle(), + item.getSite().getName()) + ); viewHolder.delete.clearColorFilter(); viewHolder.dateView.setText(item.getRegexDate()); viewHolder.share.setOnClickListener(v -> { @@ -105,29 +92,25 @@ public View getView(int pos, View convertView, ViewGroup parents) { shareIntent.putExtra(Intent.EXTRA_TEXT, item.getLink()); shareIntent.setType("text/plain"); getContext().startActivity(shareIntent); - Thread thread = new Thread() { - @Override - public void run() { - try { - Thread.sleep(200); - viewHolder.share.clearColorFilter(); - } catch (InterruptedException ignored) { - } - } + Runnable sleep = () -> { + try { Thread.sleep(200); } + catch (Exception ignored) {} + viewHolder.share.clearColorFilter(); }; - thread.start(); + Thread sleepThread = new Thread(sleep); + sleepThread.start(); }); View finalConvertView = convertView; viewHolder.like.setOnClickListener(v -> { try { - for (NewsRssItem loopItem : NewsRssItem.getLikedNews()) { + for (NewsRssItem loopItem : NewsRssItemManager.getInstance().getLikedNews()) { if (loopItem.isEqual(item)) { Snackbar.make(finalConvertView, getContext().getString(R.string.str_already_liked), Snackbar.LENGTH_SHORT).show(); return; } } - NewsRssItem.getLikedNews().add(item); + NewsRssItemManager.getInstance().getLikedNews().add(item); viewHolder.like.setColorFilter(R.color.black); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); @@ -142,13 +125,10 @@ public void run() { urlElem.appendChild(document.createTextNode(item.getLink())); Element dateElem = document.createElement("pubDate"); dateElem.appendChild(document.createTextNode(item.getDate().toString())); - Element imageElement = document.createElement("image"); - imageElement.appendChild(document.createTextNode(item.getUrlImage())); itemElem.appendChild(nameElem); itemElem.appendChild(siteElem); itemElem.appendChild(urlElem); itemElem.appendChild(dateElem); - itemElem.appendChild(imageElement); rootElem.appendChild(itemElem); document.appendChild(rootElem); TransformerFactory transformerFactory = TransformerFactory.newInstance(); @@ -225,7 +205,7 @@ public void run() { getContext().openFileOutput("news.xml", Context.MODE_APPEND).write(res.getBytes()); } catch (IOException ignored) { } - NewsRssItem.getLikedNews().remove(item); + NewsRssItemManager.getInstance().getLikedNews().remove(item); this.remove(item); viewHolder.delete.clearColorFilter(); } diff --git a/app/src/main/java/com/example/project_28_02_2021/site/Site.java b/app/src/main/java/com/example/project_28_02_2021/site/Site.java new file mode 100644 index 0000000..8384438 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/site/Site.java @@ -0,0 +1,46 @@ +package com.example.project_28_02_2021.site; + +import android.content.Context; + +import com.example.project_28_02_2021.rss.NewsRssItem; +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.rss.NewsRssItemManager; + +public class Site { + private final String name; + private final String url; + private String imageLink = "no_link"; + private SiteStatusStates status = SiteStatusStates.UNFILLED_STATE; + private final Context context; + + public Site(String name, String url, Context context) { + this.name = name; + this.url = url; + this.context = context; + } + + public String asString() { + return context.getString(R.string.str_site_data, name, url) + .replaceAll(".xml", "") + .replaceAll("://", "") + .replaceAll("https", "") + .replaceAll("http", "") + .replaceAll("ftp", "") + .replaceAll("ftps", ""); + } + + public int getItemsCount() { + int newsCount = 0; + for (NewsRssItem item : NewsRssItemManager.getInstance().getNews()) + if (item.getSite().getName().equals(name)) + newsCount++; + return newsCount; + } + + public void setStatus(SiteStatusStates status) { this.status = status; } + public String getName() { return name; } + public String getUrl() { return url; } + public void setImageLink(String imageLink) { this.imageLink = imageLink; } + public String getImageLink() { return imageLink; } + public SiteStatusStates getStatus() { return status; } +} diff --git a/app/src/main/java/com/example/project_28_02_2021/site/SiteManager.java b/app/src/main/java/com/example/project_28_02_2021/site/SiteManager.java new file mode 100644 index 0000000..de5c5c6 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/site/SiteManager.java @@ -0,0 +1,44 @@ +package com.example.project_28_02_2021.site; + +import android.content.Context; + +import com.example.project_28_02_2021.util.database.DataBaseHelper; + +import java.util.ArrayList; + +public class SiteManager { + private final ArrayList site_list = new ArrayList<>(); + private final DataBaseHelper helper; + private static SiteManager manager = null; + + public static SiteManager getInstance(Context context, ArrayList exe_rows) { + if (manager == null) { manager = new SiteManager(context, exe_rows); } + return manager; + } + + private SiteManager(Context context, ArrayList exe_rows) { + helper = new DataBaseHelper(context, exe_rows); + helper.getReadableDatabase(); + site_list.addAll(helper.getSites()); + } + + public ArrayList getSites() { return site_list; } + + public void addSite(Site site) { + site_list.add(site); + helper.addSite(site); + } + + public void deleteSite(Site site) { + helper.getReadableDatabase(); + site_list.remove(site); + helper.deleteSite(site); + } + + public Site getSiteByName(String name, Context context) { + for (Site site : site_list) + if (site.getName().equals(name)) + return site; + return new Site(name, "?", context); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/site/SiteStatusStates.java b/app/src/main/java/com/example/project_28_02_2021/site/SiteStatusStates.java new file mode 100644 index 0000000..0c2b38d --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/site/SiteStatusStates.java @@ -0,0 +1,7 @@ +package com.example.project_28_02_2021.site; + +public enum SiteStatusStates { + FILLED_STATE, + UNFILLED_STATE, + UNKNOWN_STATE, +} \ No newline at end of file diff --git a/app/src/main/java/com/example/project_28_02_2021/SiteAdapter.java b/app/src/main/java/com/example/project_28_02_2021/site/adapter/SiteAdapter.java similarity index 52% rename from app/src/main/java/com/example/project_28_02_2021/SiteAdapter.java rename to app/src/main/java/com/example/project_28_02_2021/site/adapter/SiteAdapter.java index 8e18c44..b5f2862 100644 --- a/app/src/main/java/com/example/project_28_02_2021/SiteAdapter.java +++ b/app/src/main/java/com/example/project_28_02_2021/site/adapter/SiteAdapter.java @@ -1,6 +1,5 @@ -package com.example.project_28_02_2021; +package com.example.project_28_02_2021.site.adapter; -import android.app.AlertDialog; import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -9,9 +8,10 @@ import android.widget.ImageView; import android.widget.TextView; +import com.example.project_28_02_2021.R; +import com.example.project_28_02_2021.site.Site; import com.squareup.picasso.Picasso; -import java.util.ArrayList; import java.util.List; public class SiteAdapter extends ArrayAdapter { @@ -40,17 +40,11 @@ public ViewHolder(View view) { } private void picIntoViewByLink(String link, ImageView view) { - if (!"Done".contentEquals(view.getContentDescription())) { Context context = getContext(); context.getAssets(); view.setImageResource(R.drawable.rss_icon); - try { - Picasso.with(context).load(link).error(R.drawable.rss_icon).into(view); - } catch (Exception e) { - view.setImageResource(R.drawable.rss_icon); - } - view.setContentDescription("Done"); - } + try { Picasso.with(context).load(link).error(R.drawable.rss_icon).into(view); } + catch (Exception e) { view.setImageResource(R.drawable.rss_icon); } } @Override @@ -60,38 +54,17 @@ public View getView(int pos, View convertView, ViewGroup parents) { convertView = inflater.inflate(layoutRes, parents, false); viewHolder = new SiteAdapter.ViewHolder(convertView); convertView.setTag(viewHolder); - } else { - viewHolder = (SiteAdapter.ViewHolder) convertView.getTag(); - } + } else { viewHolder = (SiteAdapter.ViewHolder) convertView.getTag(); } Site item = items.get(pos); picIntoViewByLink(item.getImageLink(), viewHolder.site_icon); - viewHolder.infoView.setText(item.asString()); + String plural = getContext().getResources().getQuantityString( + R.plurals.items_plurals, + item.getItemsCount() + ); viewHolder.quantity_view.setText( - getContext().getString(R.string.str_items_count, - item.getItemsCount(), - getContext().getResources().getQuantityString(R.plurals.items_plurals, item.getItemsCount())) + getContext().getString(R.string.str_items_count, item.getItemsCount(), plural) ); - convertView.setOnLongClickListener(v -> { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - AlertDialog dialog = builder - .setTitle(R.string.str_delete_full_site) - .setMessage(getContext().getString(R.string.str_sure, item.getName())) - .setPositiveButton(R.string.str_delete_site, - (dialog1, which) -> { - Site.getSites().remove(item); - this.remove(item); - DataBaseHelper helper = new DataBaseHelper(getContext(), new ArrayList<>()); - helper.getReadableDatabase(); - helper.deleteSite(item); - } - ) - .setNegativeButton(R.string.str_add_site_neg_button, (dialog12, which) -> { - }) - .create(); - dialog.show(); - return true; - }); return convertView; } } diff --git a/app/src/main/java/com/example/project_28_02_2021/DataBaseHelper.java b/app/src/main/java/com/example/project_28_02_2021/util/database/DataBaseHelper.java similarity index 54% rename from app/src/main/java/com/example/project_28_02_2021/DataBaseHelper.java rename to app/src/main/java/com/example/project_28_02_2021/util/database/DataBaseHelper.java index 05daf9b..1c159d4 100644 --- a/app/src/main/java/com/example/project_28_02_2021/DataBaseHelper.java +++ b/app/src/main/java/com/example/project_28_02_2021/util/database/DataBaseHelper.java @@ -1,29 +1,43 @@ -package com.example.project_28_02_2021; +package com.example.project_28_02_2021.util.database; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import com.example.project_28_02_2021.site.Site; + import java.util.ArrayList; public class DataBaseHelper extends SQLiteOpenHelper { - protected final ArrayList rows = new ArrayList<>(); + protected final ArrayList exe_rows = new ArrayList<>(); protected final Context context; + public static String tableName + = "sites_table"; + public static String databaseName + = "sites_base.db"; + public static String assetName + = "sites_table.sql"; + public static String deleteQuery - = "delete from sites_table where name = '%s';"; + = "delete from " + tableName + " where name = '%s';"; public static String addQuery - = "insert into sites_table values ('%s', '%s');"; + = "insert into " + tableName + " values ('%s', '%s');"; public static String selectQuery - = "select name, url from sites_table"; + = "select name, url from " + tableName; + public static String createQuery - = "create table sites_table\n(\n name text not null,\n url text not null\n);"; + = "create table " + tableName + "\n" + + "(" + "\n" + + " name text not null, " + "\n" + + " url text not null " + "\n" + + ");"; public DataBaseHelper(Context context, ArrayList rows) { - super(context, "sites_base.db", null, 1); - this.rows.addAll(rows); + super(context, databaseName, null, 1); + this.exe_rows.addAll(rows); this.context = context; } @@ -38,25 +52,25 @@ public void addSite(Site site) { @Override public void onCreate(SQLiteDatabase db) { db.execSQL(createQuery); - for (String row : rows) { + for (String row : exe_rows) db.execSQL(row); - } } @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - } + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} public ArrayList getSites() { Cursor cursor = getReadableDatabase().rawQuery(selectQuery, null); ArrayList sites = new ArrayList<>(); + final String name_str = "name"; + final String url_str = "url"; while (cursor.moveToNext()) { - int nameId = cursor.getColumnIndex("name"); - int urlId = cursor.getColumnIndex("url"); + int nameId = cursor.getColumnIndex(name_str); + int urlId = cursor.getColumnIndex(url_str); String name = cursor.getString(nameId); String url = cursor.getString(urlId); - Site site = new Site(name, url, context); - sites.add(site); + Site new_site = new Site(name, url, context); + sites.add(new_site); } cursor.close(); return sites; diff --git a/app/src/main/java/com/example/project_28_02_2021/util/files/FileManager.java b/app/src/main/java/com/example/project_28_02_2021/util/files/FileManager.java new file mode 100644 index 0000000..bb70246 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/util/files/FileManager.java @@ -0,0 +1,47 @@ +package com.example.project_28_02_2021.util.files; + +import android.content.Context; +import android.content.res.AssetManager; + +import com.example.project_28_02_2021.util.database.DataBaseHelper; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Scanner; + +public class FileManager { + + public static String readFile(Context context, String name) throws FileNotFoundException { + context.openFileOutput(name, Context.MODE_APPEND); + InputStream stream = context.openFileInput(name); + StringBuilder gotXml = new StringBuilder(); + Scanner scanner = new Scanner(stream); + while (scanner.hasNext()) + gotXml.append(scanner.next()); + return gotXml.toString(); + } + + + public static void deleteFile(Context context, String name) { + context.deleteFile(name); + } + + public static ArrayList getAssetData(AssetManager manager) throws IOException { + ArrayList exe_rows = new ArrayList<>(); + InputStream inputStream = manager.open(DataBaseHelper.assetName); + Scanner scanner = new Scanner(inputStream); + while (scanner.hasNext()) exe_rows.add(scanner.nextLine()); + inputStream.close(); + scanner.close(); + return exe_rows; + } + + public static String liked_news_storage + = "news.xml"; + public static String deleted_news_storage + = "read.xml"; + public static String tags_storage + = "tags.xml"; +} diff --git a/app/src/main/java/com/example/project_28_02_2021/util/net/NetLoader.java b/app/src/main/java/com/example/project_28_02_2021/util/net/NetLoader.java new file mode 100644 index 0000000..d0febfc --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/util/net/NetLoader.java @@ -0,0 +1,53 @@ +package com.example.project_28_02_2021.util.net; + +import android.content.Context; + +import com.example.project_28_02_2021.rss.NewsRssItem; +import com.example.project_28_02_2021.rss.NewsRssItemManager; +import com.example.project_28_02_2021.site.Site; +import com.example.project_28_02_2021.site.SiteStatusStates; +import com.example.project_28_02_2021.util.files.FileManager; +import com.example.project_28_02_2021.util.xml.XmlFeedParser; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.parser.Parser; +import org.jsoup.select.Elements; + +import java.io.IOException; + +public class NetLoader { + + public static Document getSiteContent(Site site) throws IOException { + String xml = Jsoup.connect(site.getUrl()).get().toString(); + return Jsoup.parse(xml, "", Parser.xmlParser()); + } + + public static void loadFromSite(Context context, Site from) { + Runnable load = () -> { + try { + Document doc; + doc = getSiteContent(from); + Document readDoc; + readDoc = Jsoup.parse(FileManager.readFile(context, FileManager.deleted_news_storage), "", Parser.xmlParser()); + from.setImageLink(doc.select(XmlFeedParser.image_tag).select(XmlFeedParser.url_tag).text()); + for (Element el : doc.select(XmlFeedParser.item_tag)) { + NewsRssItem item = XmlFeedParser.parseItemFromXml(el, from, context); + boolean notRead = true; + Elements items = readDoc.select(XmlFeedParser.item_tag); + for (Element elem : items) + if (elem.select(XmlFeedParser.title_tag).text().equalsIgnoreCase(item.getTitle().replace(" ", ""))) + notRead = false; + boolean notAgain = true; + for (NewsRssItem rssItem : NewsRssItemManager.getInstance().getNews()) + if (rssItem.getTitle().equals(item.getTitle())) { notAgain = false; break; } + if (notRead && notAgain) NewsRssItemManager.getInstance().addNews(item); + from.setStatus(SiteStatusStates.FILLED_STATE); + } + } catch (Exception e) { from.setStatus(SiteStatusStates.UNKNOWN_STATE); } + }; + Thread load_thread = new Thread(load); + load_thread.start(); + } +} diff --git a/app/src/main/java/com/example/project_28_02_2021/PreferenceManager.java b/app/src/main/java/com/example/project_28_02_2021/util/settings/PreferenceManager.java similarity index 72% rename from app/src/main/java/com/example/project_28_02_2021/PreferenceManager.java rename to app/src/main/java/com/example/project_28_02_2021/util/settings/PreferenceManager.java index dacc5f4..c53cef6 100644 --- a/app/src/main/java/com/example/project_28_02_2021/PreferenceManager.java +++ b/app/src/main/java/com/example/project_28_02_2021/util/settings/PreferenceManager.java @@ -1,4 +1,4 @@ -package com.example.project_28_02_2021; +package com.example.project_28_02_2021.util.settings; import android.content.Context; import android.content.SharedPreferences; @@ -8,20 +8,14 @@ public class PreferenceManager { private final SharedPreferences.Editor editor; public static class PreferencePair { - String key, value; - + final String key; + final String value; + public String getKey() { return key; } + public String getValue() { return value; } public PreferencePair(String key, String value) { this.key = key; this.value = value; } - - public String getKey() { - return key; - } - - public String getValue() { - return value; - } } public PreferenceManager(Context context) { @@ -32,13 +26,19 @@ public PreferenceManager(Context context) { } public void setValueByKey(PreferencePair... pairs) { - for (PreferencePair pair : pairs) { - editor.putString(pair.getKey(), pair.getValue()); - } + for (PreferencePair pair : pairs) + editor.putString( + pair.getKey(), pair.getValue() + ); editor.apply(); editor.commit(); } + public String getString(String key, String def, Context context) { + SharedPreferences settings = context.getSharedPreferences(SETTINGS_NAME, Context.MODE_MULTI_PROCESS); + return settings.getString(key, def); + } + public final static String SETTINGS_NAME = "settings"; public final static String SORT_KEY diff --git a/app/src/main/java/com/example/project_28_02_2021/util/xml/XmlCreator.java b/app/src/main/java/com/example/project_28_02_2021/util/xml/XmlCreator.java new file mode 100644 index 0000000..e344337 --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/util/xml/XmlCreator.java @@ -0,0 +1,4 @@ +package com.example.project_28_02_2021.util.xml; + +public class XmlCreator { +} diff --git a/app/src/main/java/com/example/project_28_02_2021/util/xml/XmlFeedParser.java b/app/src/main/java/com/example/project_28_02_2021/util/xml/XmlFeedParser.java new file mode 100644 index 0000000..5a94a1b --- /dev/null +++ b/app/src/main/java/com/example/project_28_02_2021/util/xml/XmlFeedParser.java @@ -0,0 +1,53 @@ +package com.example.project_28_02_2021.util.xml; + +import android.content.Context; + +import com.example.project_28_02_2021.rss.NewsRssItem; +import com.example.project_28_02_2021.site.Site; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.parser.Parser; + +import java.util.ArrayList; + +public class XmlFeedParser { + + public static NewsRssItem parseItemFromXml(Element element, Site from, Context context) { + return new NewsRssItem( + from, element.select(link_tag).text(), + element.select(title_tag).text(), + element.select(category_tag).text().toLowerCase() + + " " + element.select(description_tag).text().toLowerCase() + + " " + from.getName().toLowerCase(), + element.select(pubDate_tag).text(), + context); + } + + public static ArrayList parseFeedFromXml(String feed, Site from, Context context) { + Parser parser = Parser.xmlParser(); + Document doc = Jsoup.parse(feed, "", parser); + ArrayList items = new ArrayList<>(); + for (Element element : doc.select(item_tag)) + items.add(parseItemFromXml(element, from, context)); + return items; + } + + public static String item_tag + = "item"; + public static String link_tag + = "link"; + public static String url_tag + = "url"; + public static String title_tag + = "title"; + public static String category_tag + = "category"; + public static String description_tag + = "description"; + public static String pubDate_tag + = "pubDate"; + public static String image_tag + = "image"; +} diff --git a/app/src/main/res/layout/activity_favorites.xml b/app/src/main/res/layout/activity_favorites.xml new file mode 100644 index 0000000..e951ff5 --- /dev/null +++ b/app/src/main/res/layout/activity_favorites.xml @@ -0,0 +1,36 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_liked_news_activity.xml b/app/src/main/res/layout/activity_liked_news_activity.xml deleted file mode 100644 index 9a391e3..0000000 --- a/app/src/main/res/layout/activity_liked_news_activity.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index a6821cb..7812d28 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivity"> + tools:context=".activity.MainActivity"> + tools:context=".activity.SettingsActivity"> + + + tools:context=".activity.SplashActivity"> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/favorites_header.xml b/app/src/main/res/layout/favorites_header.xml new file mode 100644 index 0000000..ef4432b --- /dev/null +++ b/app/src/main/res/layout/favorites_header.xml @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 607a96e..5b75a27 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -65,4 +65,9 @@ разрешение на автозапуск, а также на отображение на экране блокировки, отображение всплывающих окон в фоновом режиме, показ постоянных уведомлений. Ок + Подключение восстановлено + Избранные не содержат ни одной новости. + Нажмите, чтобы вернуться в начало. + Добро пожаловать в избранное.\nНажмите, чтобы попасть в конец. + База данных не содержит ни одного сайта. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 4d24be2..141cc76 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,10 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() jcenter() } dependencies { - classpath "com.android.tools.build:gradle:4.1.1" - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files + classpath "com.android.tools.build:gradle:4.1.2" } }