diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 0000000..f47ae74
--- /dev/null
+++ b/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/MainActivity.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/MainActivity.kt
index 4eca205..e43e404 100644
--- a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/MainActivity.kt
+++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/MainActivity.kt
@@ -6,13 +6,11 @@ import android.util.Log
import android.widget.ScrollView
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.*
@@ -22,14 +20,21 @@ import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.fragment.app.Fragment
+import coil.compose.rememberImagePainter
+import com.google.accompanist.swiperefresh.SwipeRefresh
+import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
import eu.toldi.balazs.anotherfeedreader.entities.Article
import eu.toldi.balazs.anotherfeedreader.entities.Feed
+import eu.toldi.balazs.anotherfeedreader.entities.FeedGroup
import eu.toldi.balazs.anotherfeedreader.ui.theme.AnotherFeedReaderTheme
import java.net.URL
import java.time.LocalDateTime
@@ -38,7 +43,10 @@ import java.time.format.FormatStyle
class MainActivity : ComponentActivity() {
- val feed = Feed(URL("https://hvg.hu/rss"))
+ val feed = FeedGroup("magyar").apply {
+ addFeed(Feed(URL("https://hvg.hu/rss")))
+ addFeed(Feed(URL("https://telex.hu/rss")))
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -47,34 +55,50 @@ class MainActivity : ComponentActivity() {
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
- var articleCount = remember { mutableStateOf(feed.articleCount) }
- Log.w(null,articleCount.toString())
+ feed.updateFeed()
+ var articleList = remember { mutableStateOf(feed.articleList) }
+
+
+ Log.w(null, articleList.value.size.toString())
Column {
MenuBar()
- val scrollState = rememberScrollState()
- LazyColumn(
- modifier = Modifier.scrollable(
- state = scrollState,
- orientation = Orientation.Vertical
- )
+ val isRefreshing by feed.isRefreshing.collectAsState()
+ SwipeRefresh(
+ state = rememberSwipeRefreshState(isRefreshing),
+ onRefresh = {
+ feed.updateFeed()
+ articleList.value = feed.articleList
+ },
) {
- items(articleCount.value) { index ->
- Column(
- Modifier
- .clickable {
- Log.i(null, feed[index].title.toString())
- WebView.webURL = feed[index].url.toString()
- WebView.barTitle = feed.name.toString()
- startActivity(Intent(baseContext, WebView::class.java))
- }
- .padding(
- horizontal = 3.dp
- )
- ) {
- showArticle(article = feed[index], feed.name!!)
- }
+ LazyColumn(
+ modifier = Modifier.fillMaxHeight()
+ ) {
+ items(articleList.value.size) { index ->
+ val article = articleList.value[index]
+ Column(
+
+ Modifier
+ .clickable {
+ Log.i(null, article.title.toString())
+ WebView.webURL = article.url.toString()
+ WebView.barTitle = feed.name.toString()
+ startActivity(
+ Intent(
+ baseContext,
+ WebView::class.java
+ )
+ )
+ }
+ .padding(
+ horizontal = 3.dp
+ )
+ ) {
+ showArticle(article = article, feed.name!!)
+ }
+
+ }
}
}
@@ -119,44 +143,52 @@ class MainActivity : ComponentActivity() {
@Composable
fun showArticle(article: Article, feedName: String) {
- Column(modifier = Modifier.padding(all = 5.dp)) {
- Row {
- if (article.author != null) {
+ Row {
+ Column(Modifier.weight(1f)) {
+ Row {
+ if (article.author != null) {
+ Text(
+ article.author,
+ fontSize = 11.sp
+ )
+ } else Text("")
Text(
- article.author,
- fontSize = 11.sp
- )
- } else Text("")
- Text(
- feedName,
- fontSize = 11.sp,
- textAlign = TextAlign.Center,
- modifier = Modifier.padding(horizontal = 10.dp)
- )
- if (article.pubDate != null) {
- Text(
- article.pubDate.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)),
+ feedName,
fontSize = 11.sp,
- textAlign = TextAlign.Right,
- modifier = Modifier.width(400.dp)
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(horizontal = 10.dp)
+ )
+ if (article.pubDate != null) {
+ Text(
+ article.pubDate.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)),
+ fontSize = 11.sp,
+ textAlign = TextAlign.Right,
+ //modifier = Modifier.width(350.dp)
+ )
+ } else Text("")
+ }
+ if (article.title != null) {
+ Text(
+ text = article.title.trim(),
+ fontSize= 20.sp,
+ maxLines = 2,
+ overflow = TextOverflow.Ellipsis
)
} else Text("")
+ if (article.description != null) {
+ Text(
+ text = article.description,
+ fontSize = 17.sp,
+ maxLines = 2,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
}
- if (article.title != null) {
- Text(
- text = article.title.trim(),
- maxLines = 2,
- overflow = TextOverflow.Ellipsis
+ if (article.imageURL != null)
+ Image(
+ painter = rememberImagePainter(article.imageURL),
+ contentDescription = null,
)
- } else Text("")
- if (article.description != null) {
- Text(
- text = article.description,
- fontSize = 12.sp,
- maxLines = 2,
- overflow = TextOverflow.Ellipsis
- )
- }
}
}
@@ -170,10 +202,11 @@ class MainActivity : ComponentActivity() {
title = "Teszt Article",
description = "Ez az cikk azért létezik, hogy kipróbájam a cikkek megjelenítését.",
author = "Toldi Balázs",
- pubDate = LocalDateTime.now()
+ pubDate = LocalDateTime.now(),
+ imageURL = "https://cloud.toldi.eu/index.php/apps/files_sharing/publicpreview/Aicw77SAJYBiM8B?x=1920&y=571&a=true&file=P2.JPG&scalingup=0"
)
Column(
- modifier = Modifier.padding( horizontal = 1.dp)
+ modifier = Modifier.padding(horizontal = 1.dp)
) {
showArticle(article, "Test feed")
showArticle(
diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/WebView.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/WebView.kt
index 3cc983f..09ae7d4 100644
--- a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/WebView.kt
+++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/WebView.kt
@@ -5,10 +5,9 @@ import android.webkit.WebView
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Surface
-import androidx.compose.material.Text
-import androidx.compose.material.TopAppBar
+import androidx.compose.material.*
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.OpenInBrowser
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView
@@ -17,6 +16,14 @@ import eu.toldi.balazs.anotherfeedreader.WebView.Companion.webURL
import eu.toldi.balazs.anotherfeedreader.ui.theme.AnotherFeedReaderTheme
import eu.toldi.balazs.anotherfeedreader.views.CustomWebViewClient
+import android.net.Uri
+
+import android.content.Intent
+import androidx.compose.material.icons.filled.ArrowLeft
+import androidx.core.content.ContextCompat
+import androidx.core.content.ContextCompat.startActivity
+
+
class WebView : ComponentActivity() {
companion object {
var webURL = "http://example.rog"
@@ -25,44 +32,70 @@ class WebView : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
setContent {
AnotherFeedReaderTheme {
+
// A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) {
Column() {
TopBar(topTitle = barTitle)
- ShowWebView("Android")
+ ShowWebView("Android")
}
}
}
}
}
-}
-@Composable
-fun TopBar(topTitle: String) {
- TopAppBar (
- title = { Text(text = topTitle) }
- )
-}
-@Composable
-fun ShowWebView(name: String) {
- AndroidView(factory = { ctx ->
- WebView(ctx).apply {
- loadUrl(webURL)
- webViewClient = CustomWebViewClient()
- }
- })
-}
+ @Composable
+ fun TopBar(topTitle: String) {
+
+ TopAppBar(
+ title = { Text(text = topTitle) },
+ navigationIcon = {
+ IconButton(onClick = {
+ finish()
+ }) {
+ Icon(
+ Icons.Filled.ArrowLeft,
+ contentDescription = "Back to feed"
+ )
+ }
+ },
+ actions = {
+ IconButton(onClick = {
+
+ val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(webURL))
+ startActivity(browserIntent)
+ }) {
+ Icon(
+ Icons.Filled.OpenInBrowser,
+ contentDescription = "Open in browser"
+ )
+ }
+ }
+ )
+ }
+
+ @Composable
+ fun ShowWebView(name: String) {
+ AndroidView(factory = { ctx ->
+ WebView(ctx).apply {
+ loadUrl(webURL)
+ webViewClient = CustomWebViewClient()
+ }
+ })
+ }
+
+ @Preview(showBackground = true)
+ @Composable
+ fun DefaultPreview() {
+ AnotherFeedReaderTheme {
+ Column {
+ TopBar("WebView")
+ ShowWebView("Android")
+ }
-@Preview(showBackground = true)
-@Composable
-fun DefaultPreview() {
- AnotherFeedReaderTheme {
- Column {
- TopBar("WebView")
- ShowWebView("Android")
}
-
}
}
\ No newline at end of file
diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/Feed.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/Feed.kt
index e20370d..8bc23f9 100644
--- a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/Feed.kt
+++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/Feed.kt
@@ -3,6 +3,9 @@ package eu.toldi.balazs.anotherfeedreader.entities
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.w3c.dom.Document
@@ -13,7 +16,7 @@ import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory
-class Feed
+open class Feed
(
/**
* A hírcsatorna elérési útvonala
@@ -26,12 +29,17 @@ class Feed
* A hírcsatorna neve
*/
var name: String? = null
-
+ constructor(name : String) : this(URL("http://example.com")) {
+ this.name = name
+ }
/**
* A hírcsatornához tartozó cikkek listája
*/
- val articleList: MutableList = ArrayList()
+ var articleList: List = ArrayList()
+ private val _isRefreshing = MutableStateFlow(false)
+ val isRefreshing: StateFlow
+ get() = _isRefreshing.asStateFlow()
init {
updateFeed()
}
@@ -40,7 +48,7 @@ class Feed
* A hírcsatornán található cikkek számának lekérése
* @return a hírcsatorna található cikkek száma
*/
- val articleCount: Int
+ open val articleCount: Int
get() = articleList.size
/**
@@ -57,8 +65,9 @@ class Feed
* Lekéri a hírcsatorna elérési útvonalán található összes új cikket és hozzáadja a cikkek listájához.
*
*/
- fun updateFeed() {
+ open fun updateFeed() {
GlobalScope.launch {
+ _isRefreshing.emit(true)
val factory: DocumentBuilderFactory = DocumentBuilderFactory.newInstance()
val builder: DocumentBuilder = factory.newDocumentBuilder()
var doc: Document
@@ -74,6 +83,7 @@ class Feed
addArticle(a)
}
Log.e(null, articleCount.toString())
+ _isRefreshing.emit(false)
}
}
@@ -96,7 +106,7 @@ class Feed
* Megjegyzés: cikket csak akkor veszi fel,ha az még nem található a listájában
*/
fun addArticle(a: Article) {
- if (!hasAricle(a)) articleList.add(a)
+ if (!hasAricle(a)) articleList += a
}
diff --git a/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/FeedGroup.kt b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/FeedGroup.kt
new file mode 100644
index 0000000..4ac8d00
--- /dev/null
+++ b/app/src/main/java/eu/toldi/balazs/anotherfeedreader/entities/FeedGroup.kt
@@ -0,0 +1,107 @@
+package eu.toldi.balazs.anotherfeedreader.entities
+
+import java.util.ArrayList
+
+import java.io.IOException
+
+
+class FeedGroup(name: String) : Feed(name) {
+ /**
+ * A hírcsatornák listája
+ */
+ var feedList: MutableList = ArrayList()
+
+ /**
+ * Hírcsatorna hozzáadása a csoporthoz
+ * @param feed hozzáadandó hírcsatorna
+ * Megjegyzés: Meglévő csatorna nem adható hozzá mégegyszer
+ */
+ fun addFeed(feed: Feed) {
+ if (!feedExists(feed)) {
+ feedList.add(feed)
+ for (i in 0 until feed.articleCount) {
+ if (!hasAricle(feed[i]))
+ articleList += feed[i]
+ }
+ }
+ }
+
+ /**
+ * Ellenőrzi,hogy a megadott hírcsatorna metalálható-e benne
+ * @param f az ellenőrizendő csatorna
+ * @return logikai érték az alapján,hogy a csatorna megtalálható-e a csoportban
+ * Megjegyzés: Csak abban az esetben tér vissza igazzal,ha a két objektum megegyezik egy a csoportban találhatóval
+ */
+ fun feedExists(f: Feed): Boolean {
+ for (i in feedList.indices) {
+ if (f === feedList[i]) return true
+ }
+ return false
+ }
+
+ /**
+ * @see Feed.updateFeed
+ * @throws IOException
+ */
+ override fun updateFeed() {
+ if(feedList == null) feedList = ArrayList()
+ if (articleList == null) articleList = ArrayList()
+ for (f in feedList) {
+ f.updateFeed()
+ for (i in 0 until f.articleCount) {
+ if (!hasAricle(f[i]))
+ articleList += f[i]
+ }
+ }
+ articleList = articleList.sortedByDescending { it.pubDate }
+ }
+
+ /**
+ * @see Feed.getArticleCount
+ * @return
+ */
+ override val articleCount: Int
+ get() {
+ var result = 0
+ for (f in feedList) {
+ result += f.articleCount
+ }
+ return result
+ }
+
+ /**
+ * Hírcsatorna törlése a csoportból
+ * @param feed a törlendő hírcsatorna
+ * Megjegyzés: Ez törli az össze a csatornához tartozó cikket.
+ */
+ fun removeFeed(feed: Feed) {
+ var found = false
+ for (i in feedList.indices) {
+ //Csak ha PONTOSAN megegyezik
+ if (feedList[i] === feed) {
+ feedList.removeAt(i)
+ found = true
+ break
+ }
+ }
+ if (found) {
+ val similar: MutableList = ArrayList(articleList)
+ val different: MutableList = ArrayList()
+ different.addAll(articleList)
+ different.addAll(feed.articleList)
+ similar.retainAll(feed.articleList)
+ different.removeAll(similar)
+ articleList = different
+ }
+ }
+
+ /**
+ * Egy hírcsatorna áthelyezése a listában. Átrendezésre használatos.
+ * @param f az áthelyezendő hírcsatorna
+ * @param index a hírcsatorna új helye
+ */
+ fun setLocation(f: Feed, index: Int) {
+ feedList.remove(f)
+ feedList.add(index, f)
+ }
+}