diff --git a/API/main.py b/API/main.py index 70ad027..50059cb 100644 --- a/API/main.py +++ b/API/main.py @@ -4,6 +4,7 @@ import random import feedparser import jwt +from sqlalchemy import desc from data.connect import init_db, connect, User, Document, DocumentCategory, Comment, Event from flask import Flask, Response, request, jsonify @@ -315,7 +316,7 @@ def get_events(): resp = [] with connect() as session: - events = session.query(Event).all() + events = session.query(Event).order_by(desc(Event.datetime_event)).all() users = session.query(User).all() for event in events: diff --git a/Mobile/app/src/main/java/com/example/russionroadsapp/API.kt b/Mobile/app/src/main/java/com/example/russionroadsapp/API.kt index 5899b70..2ea818b 100644 --- a/Mobile/app/src/main/java/com/example/russionroadsapp/API.kt +++ b/Mobile/app/src/main/java/com/example/russionroadsapp/API.kt @@ -30,4 +30,24 @@ object API { } } } + + @OptIn(DelicateCoroutinesApi::class) + fun getEvents(onFinish: (String) -> Unit) { + GlobalScope.launch(Dispatchers.IO) { + val reqURL = URL("$API_BASE_URL/events") + val connection = reqURL.openConnection() as HttpURLConnection + connection.requestMethod = "GET" + + if (connection.responseCode == 200) { + val resp = BufferedReader( + InputStreamReader(connection.inputStream) + ).use { it.readText() } + + onFinish(resp) + } else { + onFinish("Error") + } + } + } + } diff --git a/Mobile/app/src/main/java/com/example/russionroadsapp/MainActivity.kt b/Mobile/app/src/main/java/com/example/russionroadsapp/MainActivity.kt index 1872528..4d93de9 100644 --- a/Mobile/app/src/main/java/com/example/russionroadsapp/MainActivity.kt +++ b/Mobile/app/src/main/java/com/example/russionroadsapp/MainActivity.kt @@ -1,5 +1,6 @@ package com.example.russionroadsapp +import android.content.Context import android.os.Bundle import android.widget.Toast import androidx.activity.ComponentActivity @@ -17,6 +18,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState @@ -26,6 +28,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowForward import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Star import androidx.compose.material3.Button import androidx.compose.material3.ButtonColors import androidx.compose.material3.Icon @@ -41,6 +44,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.layout.ContentScale @@ -57,163 +61,396 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { - val listState = rememberLazyListState() - val coroutineScope = rememberCoroutineScope() - - var messageToast by remember { - mutableStateOf("") + var pageName by remember { + mutableStateOf("News") } - var newsList by remember { - mutableStateOf(listOf>()) + fun setPageNews() { + pageName = "News" } - var requestNews by remember { - mutableStateOf(true) + fun setPageEvents() { + pageName = "Events" } - var newsString by remember { - mutableStateOf("") - } - - if (messageToast != "") { - Toast.makeText( + if (pageName == "News") { + NewsPage( this@MainActivity, - messageToast, - Toast.LENGTH_LONG - ).show() - messageToast = "" + { + setPageNews() + }, + { + setPageEvents() + }, + ) + } else { + EventsPage( + this@MainActivity, + { + setPageNews() + }, + { + setPageEvents() + }, + ) } + } + } +} - LaunchedEffect(requestNews) { - if (requestNews) { - API.getNews { resp -> - if (resp != "Error") { - newsString = resp - } else { - messageToast = "Ошибка при получении новостей" - } - } +@Composable +fun EventCard(event: Map) { + Column( + Modifier + .clip(RoundedCornerShape(10.dp)) + .size(300.dp, 90.dp) + .background(Color(64, 208, 25, 255)) + .padding(10.dp), + verticalArrangement = Arrangement.SpaceAround, + ) { + Row( + Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text("") + Column { + event["title"]?.let { Text(it) } + event["description"]?.let { Text(it) } + } + Icon(Icons.Default.Star, contentDescription = "") + } + Row( + Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + event["date"]?.let { Text(it) } + event["author"]?.let { Text(it) } + } + } +} + +@Composable +fun EventsPage(localContext: Context, setPageNews: () -> Unit, setPageEvents: () -> Unit) { + + val listState = rememberLazyListState() + val coroutineScope = rememberCoroutineScope() + + var requestEvents by remember { + mutableStateOf(true) + } + + var eventsString by remember { + mutableStateOf("") + } + + var messageToast by remember { + mutableStateOf("") + } + + var eventsList by remember { + mutableStateOf(listOf>()) + } + + if (messageToast != "") { + Toast.makeText( + localContext, + messageToast, + Toast.LENGTH_LONG + ).show() + messageToast = "" + } + + LaunchedEffect(requestEvents) { + if (requestEvents) { + API.getEvents { resp -> + if (resp != "Error") { + eventsString = resp + } else { + messageToast = "Ошибка при получении событий" } } + requestEvents = false + } + } - LaunchedEffect(newsString) { - if (newsString != "") { - val gson = Gson() - val dataType = object : TypeToken>>() {}.type - val data: List> = gson.fromJson( - newsString, - dataType - ) - newsList = data - newsString = "" + LaunchedEffect(eventsString) { + if (eventsString != "") { + val gson = Gson() + val dataType = object : TypeToken>>() {}.type + val data: List> = gson.fromJson( + eventsString, + dataType + ) + eventsList = data + eventsString = "" - println(data) - } - } + println(data) + } + } - Column( - Modifier - .fillMaxSize() - .background(Color(72, 103, 48, 255)), - horizontalAlignment = Alignment.CenterHorizontally, + Column( + Modifier + .fillMaxSize() + .background(Color(72, 103, 48, 255)), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + + Spacer(Modifier.padding(20.dp)) + + Row { + + Button( + { + setPageNews() + }, + colors = ButtonColors( + containerColor = Color.Red, + contentColor = Color.Black, + disabledContentColor = Color.Black, + disabledContainerColor = Color.Red + ), + modifier = Modifier + .padding(10.dp) + .size(150.dp, 70.dp), + shape = RectangleShape ) { + Text("новости") + } - Spacer(Modifier.padding(20.dp)) + Button( + { + setPageEvents() + }, + colors = ButtonColors( + containerColor = Color.Yellow, + contentColor = Color.Black, + disabledContentColor = Color.Yellow, + disabledContainerColor = Color.Red + ), + modifier = Modifier + .padding(10.dp) + .size(150.dp, 70.dp), + shape = RectangleShape + ) { + Text("события") + } + } - Row { + Column( + Modifier + .fillMaxSize() + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { - Button( - { - - }, - colors = ButtonColors( - containerColor = Color.Red, - contentColor = Color.Black, - disabledContentColor = Color.Black, - disabledContainerColor = Color.Red - ), - modifier = Modifier - .padding(10.dp) - .size(150.dp, 70.dp), - shape = RectangleShape - ) { - Text("новости") - } - - Button( - { - - }, - colors = ButtonColors( - containerColor = Color.Yellow, - contentColor = Color.Black, - disabledContentColor = Color.Yellow, - disabledContainerColor = Color.Red - ), - modifier = Modifier - .padding(10.dp) - .size(150.dp, 70.dp), - shape = RectangleShape - ) { - Text("события") - } - } - - Row( - Modifier - .fillMaxSize() - .padding(20.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, - ) { - - Icon( - Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = "", - modifier = Modifier - .clip(CircleShape) - .clickable { - coroutineScope.launch { - val targetIndex = (listState.firstVisibleItemIndex - 1).coerceAtLeast(0) - listState.animateScrollToItem(targetIndex) - } - } - .padding(20.dp) - .weight(1f) - ) - - LazyRow( - state = listState, - modifier = Modifier.weight(4f), - horizontalArrangement = Arrangement.spacedBy(20.dp) - ) { - items(newsList.size) { index -> - NewsCard(newsList[index]) + Icon( + Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "", + modifier = Modifier + .clip(CircleShape) + .clickable { + coroutineScope.launch { + val targetIndex = (listState.firstVisibleItemIndex - 1).coerceAtLeast(0) + listState.animateScrollToItem(targetIndex) } } + .rotate(90f) + .padding(20.dp) + .weight(1f) + ) - Icon( - Icons.AutoMirrored.Filled.ArrowForward, - contentDescription = "", - modifier = Modifier - .clip(CircleShape) - .clickable { - coroutineScope.launch { - val targetIndex = - (listState.firstVisibleItemIndex + 1).coerceAtMost(newsList.size - 1) - listState.animateScrollToItem(targetIndex) - } - } - .padding(20.dp) - .weight(1f) - ) - + LazyColumn( + state = listState, + modifier = Modifier.weight(4f), + verticalArrangement = Arrangement.spacedBy(20.dp) + ) { + items(eventsList.size) { index -> + EventCard(eventsList[index]) } - } + Icon( + Icons.AutoMirrored.Filled.ArrowForward, + contentDescription = "", + modifier = Modifier + .clip(CircleShape) + .clickable { + coroutineScope.launch { + val targetIndex = + (listState.firstVisibleItemIndex + 1).coerceAtMost(eventsList.size - 1) + listState.animateScrollToItem(targetIndex) + } + } + .padding(20.dp) + .rotate(90f) + .weight(1f) + ) + } + + + } +} + +@Composable +fun NewsPage(localContext: Context, setPageNews: () -> Unit, setPageEvents: () -> Unit) { + + val listState = rememberLazyListState() + val coroutineScope = rememberCoroutineScope() + + var messageToast by remember { + mutableStateOf("") + } + + var newsList by remember { + mutableStateOf(listOf>()) + } + + var requestNews by remember { + mutableStateOf(true) + } + + var newsString by remember { + mutableStateOf("") + } + + if (messageToast != "") { + Toast.makeText( + localContext, + messageToast, + Toast.LENGTH_LONG + ).show() + messageToast = "" + } + + LaunchedEffect(requestNews) { + if (requestNews) { + API.getNews { resp -> + if (resp != "Error") { + newsString = resp + } else { + messageToast = "Ошибка при получении новостей" + } + } + } + } + + LaunchedEffect(newsString) { + if (newsString != "") { + val gson = Gson() + val dataType = object : TypeToken>>() {}.type + val data: List> = gson.fromJson( + newsString, + dataType + ) + newsList = data + newsString = "" + + println(data) + } + } + + Column( + Modifier + .fillMaxSize() + .background(Color(72, 103, 48, 255)), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + + Spacer(Modifier.padding(20.dp)) + + Row { + + Button( + { + setPageNews() + }, + colors = ButtonColors( + containerColor = Color.Red, + contentColor = Color.Black, + disabledContentColor = Color.Black, + disabledContainerColor = Color.Red + ), + modifier = Modifier + .padding(10.dp) + .size(150.dp, 70.dp), + shape = RectangleShape + ) { + Text("новости") + } + + Button( + { + setPageEvents() + }, + colors = ButtonColors( + containerColor = Color.Yellow, + contentColor = Color.Black, + disabledContentColor = Color.Yellow, + disabledContainerColor = Color.Red + ), + modifier = Modifier + .padding(10.dp) + .size(150.dp, 70.dp), + shape = RectangleShape + ) { + Text("события") + } + } + + Row( + Modifier + .fillMaxSize() + .padding(20.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + + Icon( + Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "", + modifier = Modifier + .clip(CircleShape) + .clickable { + coroutineScope.launch { + val targetIndex = (listState.firstVisibleItemIndex - 1).coerceAtLeast(0) + listState.animateScrollToItem(targetIndex) + } + } + .padding(20.dp) + .weight(1f) + ) + + LazyRow( + state = listState, + modifier = Modifier.weight(4f), + horizontalArrangement = Arrangement.spacedBy(20.dp) + ) { + items(newsList.size) { index -> + NewsCard(newsList[index]) + } + } + + Icon( + Icons.AutoMirrored.Filled.ArrowForward, + contentDescription = "", + modifier = Modifier + .clip(CircleShape) + .clickable { + coroutineScope.launch { + val targetIndex = + (listState.firstVisibleItemIndex + 1).coerceAtMost(newsList.size - 1) + listState.animateScrollToItem(targetIndex) + } + } + .padding(20.dp) + .weight(1f) + ) + + } + } }