2 Commits
Author SHA1 Message Date
herel efaa93d907 chore: add targets to makefile 2026-08-06 15:28:20 +02:00
herel 418a8978f2 ref: Rename package ch.parano.myice to ch.parano.myicek
Complete the MyIceK rename by updating the Kotlin package from ch.parano.myice to ch.parano.myicek across all source sets (androidMain, commonMain, desktopMain, iosMain, commonTest), the build.gradle.kts (namespace, applicationId, mainClass, desktop packageName) and the iOS Info.plist bundle URL name. The myice:// OAuth scheme is kept unchanged as it depends on the backend.

Also add pull-to-refresh to ScheduleScreen using Material 3 PullToRefreshBox, replacing the manual loading overlay.
2026-08-06 15:20:47 +02:00
53 changed files with 147 additions and 143 deletions
+10 -1
View File
@@ -1,7 +1,16 @@
.PHONY: android desktop .PHONY: android desktop android-usb android-emulator
ADB := $(shell command -v adb 2>/dev/null || echo "$(HOME)/Library/Android/sdk/platform-tools/adb")
APK := composeApp/build/outputs/apk/debug/composeApp-debug.apk
android: android:
./gradlew composeApp:assembleDebug ./gradlew composeApp:assembleDebug
desktop: desktop:
./gradlew composeApp:run ./gradlew composeApp:run
android-usb: android
$(ADB) -d install -r $(APK)
android-emulator: android
$(ADB) -e install -r $(APK)
+4 -4
View File
@@ -83,11 +83,11 @@ kotlin {
} }
android { android {
namespace = "ch.parano.myice" namespace = "ch.parano.myicek"
compileSdk = 36 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "ch.parano.myice" applicationId = "ch.parano.myicek"
minSdk = 24 minSdk = 24
targetSdk = 35 targetSdk = 35
versionCode = 1 versionCode = 1
@@ -118,10 +118,10 @@ android {
compose.desktop { compose.desktop {
application { application {
mainClass = "ch.parano.myice.MainKt" mainClass = "ch.parano.myicek.MainKt"
nativeDistributions { nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "myice" packageName = "myicek"
packageVersion = "1.0.0" packageVersion = "1.0.0"
} }
} }
@@ -15,13 +15,13 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice package ch.parano.myicek
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import ch.parano.myice.auth.AndroidOAuthClient import ch.parano.myicek.auth.AndroidOAuthClient
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -15,12 +15,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice package ch.parano.myicek
import android.app.Activity import android.app.Activity
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import ch.parano.myice.auth.OAuthCallbackHolder import ch.parano.myicek.auth.OAuthCallbackHolder
class OAuthCallbackActivity : Activity() { class OAuthCallbackActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.auth package ch.parano.myicek.auth
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.network package ch.parano.myicek.network
import io.ktor.client.engine.HttpClientEngineConfig import io.ktor.client.engine.HttpClientEngineConfig
import io.ktor.client.engine.HttpClientEngineFactory import io.ktor.client.engine.HttpClientEngineFactory
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui package ch.parano.myicek.ui
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice package ch.parano.myicek
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -24,19 +24,19 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import ch.parano.myice.auth.AuthSettings import ch.parano.myicek.auth.AuthSettings
import ch.parano.myice.auth.OAuthClient import ch.parano.myicek.auth.OAuthClient
import ch.parano.myice.cache.ScheduleCache import ch.parano.myicek.cache.ScheduleCache
import ch.parano.myice.network.ApiService import ch.parano.myicek.network.ApiService
import ch.parano.myice.network.createHttpClient import ch.parano.myicek.network.createHttpClient
import ch.parano.myice.ui.screens.EventDetailScreen import ch.parano.myicek.ui.screens.EventDetailScreen
import ch.parano.myice.ui.screens.LoginScreen import ch.parano.myicek.ui.screens.LoginScreen
import ch.parano.myice.ui.screens.ScheduleScreen import ch.parano.myicek.ui.screens.ScheduleScreen
import ch.parano.myice.ui.theme.MyIceTheme import ch.parano.myicek.ui.theme.MyIceTheme
import ch.parano.myice.viewmodel.AuthState import ch.parano.myicek.viewmodel.AuthState
import ch.parano.myice.viewmodel.AuthViewModel import ch.parano.myicek.viewmodel.AuthViewModel
import ch.parano.myice.viewmodel.EventDetailViewModel import ch.parano.myicek.viewmodel.EventDetailViewModel
import ch.parano.myice.viewmodel.ScheduleViewModel import ch.parano.myicek.viewmodel.ScheduleViewModel
import com.russhwolf.settings.Settings import com.russhwolf.settings.Settings
sealed class Screen { sealed class Screen {
@@ -15,9 +15,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.auth package ch.parano.myicek.auth
import ch.parano.myice.network.AuthTokenHolder import ch.parano.myicek.network.AuthTokenHolder
import com.russhwolf.settings.Settings import com.russhwolf.settings.Settings
class AuthSettings(private val settings: Settings) { class AuthSettings(private val settings: Settings) {
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.auth package ch.parano.myicek.auth
interface OAuthClient { interface OAuthClient {
fun redirectUri(): String fun redirectUri(): String
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.auth package ch.parano.myicek.auth
internal fun parseAccessTokenFromFragment(fragment: String): String? { internal fun parseAccessTokenFromFragment(fragment: String): String? {
val params = fragment.split("&").associate { pair -> val params = fragment.split("&").associate { pair ->
@@ -15,9 +15,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.cache package ch.parano.myicek.cache
import ch.parano.myice.models.Event import ch.parano.myicek.models.Event
import com.russhwolf.settings.Settings import com.russhwolf.settings.Settings
import kotlin.time.Clock import kotlin.time.Clock
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
@@ -15,9 +15,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.filter package ch.parano.myicek.filter
import ch.parano.myice.models.Event import ch.parano.myicek.models.Event
fun extractSubgroup(name: String): String { fun extractSubgroup(name: String): String {
val parts = name.split(" - ") val parts = name.split(" - ")
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.filter package ch.parano.myicek.filter
enum class TypeFilter { enum class TypeFilter {
ALL, GAMES, PRACTICES; ALL, GAMES, PRACTICES;
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationException import kotlinx.serialization.SerializationException
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.network package ch.parano.myicek.network
object ApiConfig { object ApiConfig {
const val baseUrl = "https://myice.parano.ch" const val baseUrl = "https://myice.parano.ch"
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.network package ch.parano.myicek.network
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.engine.HttpClientEngineConfig import io.ktor.client.engine.HttpClientEngineConfig
@@ -15,12 +15,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.network package ch.parano.myicek.network
import ch.parano.myice.models.Account import ch.parano.myicek.models.Account
import ch.parano.myice.models.Event import ch.parano.myicek.models.Event
import ch.parano.myice.models.EventDetail import ch.parano.myicek.models.EventDetail
import ch.parano.myice.models.UserInfo import ch.parano.myicek.models.UserInfo
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.call.body import io.ktor.client.call.body
import io.ktor.client.request.get import io.ktor.client.request.get
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.network package ch.parano.myicek.network
object AuthTokenHolder { object AuthTokenHolder {
var token: String? = null var token: String? = null
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui package ch.parano.myicek.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui.components package ch.parano.myicek.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -33,8 +33,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ch.parano.myice.models.Event import ch.parano.myicek.models.Event
import ch.parano.myice.util.formatEventDateTime import ch.parano.myicek.util.formatEventDateTime
@Composable @Composable
fun EventCard( fun EventCard(
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui.components package ch.parano.myicek.ui.components
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui.components package ch.parano.myicek.ui.components
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui.screens package ch.parano.myicek.ui.screens
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -45,11 +45,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ch.parano.myice.ui.PlatformBackHandler import ch.parano.myicek.ui.PlatformBackHandler
import ch.parano.myice.ui.components.LoadingIndicator import ch.parano.myicek.ui.components.LoadingIndicator
import ch.parano.myice.util.formatEventDate import ch.parano.myicek.util.formatEventDate
import ch.parano.myice.util.formatEventTimeRange import ch.parano.myicek.util.formatEventTimeRange
import ch.parano.myice.viewmodel.EventDetailViewModel import ch.parano.myicek.viewmodel.EventDetailViewModel
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui.screens package ch.parano.myicek.ui.screens
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -39,8 +39,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ch.parano.myice.viewmodel.AuthViewModel import ch.parano.myicek.viewmodel.AuthViewModel
import ch.parano.myice.viewmodel.AuthState import ch.parano.myicek.viewmodel.AuthState
@Composable @Composable
fun LoginScreen( fun LoginScreen(
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui.screens package ch.parano.myicek.ui.screens
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically import androidx.compose.animation.expandVertically
@@ -31,7 +31,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -53,12 +53,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import ch.parano.myice.filter.TypeFilter import ch.parano.myicek.filter.TypeFilter
import ch.parano.myice.ui.components.EventCard import ch.parano.myicek.ui.components.EventCard
import ch.parano.myice.ui.components.FilterDropdown import ch.parano.myicek.ui.components.FilterDropdown
import ch.parano.myice.ui.components.LoadingIndicator import ch.parano.myicek.ui.components.LoadingIndicator
import ch.parano.myice.viewmodel.AuthViewModel import ch.parano.myicek.viewmodel.AuthViewModel
import ch.parano.myice.viewmodel.ScheduleViewModel import ch.parano.myicek.viewmodel.ScheduleViewModel
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -82,7 +82,7 @@ fun ScheduleScreen(
TopAppBar( TopAppBar(
title = { Text("MyIceK") }, title = { Text("MyIceK") },
actions = { actions = {
val email = (authState as? ch.parano.myice.viewmodel.AuthState.Authenticated)?.email val email = (authState as? ch.parano.myicek.viewmodel.AuthState.Authenticated)?.email
if (email != null) { if (email != null) {
Text( Text(
text = email, text = email,
@@ -201,7 +201,9 @@ fun ScheduleScreen(
} }
} }
} }
Box( PullToRefreshBox(
isRefreshing = scheduleState.isRefreshing,
onRefresh = { scheduleViewModel.refreshSchedule() },
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
@@ -259,23 +261,6 @@ fun ScheduleScreen(
} }
} }
} }
if (scheduleState.isRefreshing) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
Card {
Column(
modifier = Modifier.padding(32.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
CircularProgressIndicator()
Spacer(modifier = Modifier.height(16.dp))
Text("Chargement...", fontWeight = FontWeight.Medium)
}
}
}
}
} }
} }
} }
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui.theme package ch.parano.myicek.ui.theme
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.util package ch.parano.myicek.util
import kotlinx.datetime.LocalDateTime import kotlinx.datetime.LocalDateTime
@@ -24,6 +24,10 @@ private val FRENCH_MONTHS = listOf(
"juillet", "août", "septembre", "octobre", "novembre", "décembre", "juillet", "août", "septembre", "octobre", "novembre", "décembre",
) )
private val FRENCH_DAYS = listOf(
"Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche",
)
private fun parseOrNull(iso: String): LocalDateTime? = runCatching { private fun parseOrNull(iso: String): LocalDateTime? = runCatching {
LocalDateTime.parse(iso.replace(' ', 'T')) LocalDateTime.parse(iso.replace(' ', 'T'))
}.getOrNull() }.getOrNull()
@@ -32,7 +36,7 @@ private fun LocalDateTime.dateStr(): String =
"${year.toString().padStart(4, '0')}-${monthNumber.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}" "${year.toString().padStart(4, '0')}-${monthNumber.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}"
private fun LocalDateTime.dateStrLong(): String = private fun LocalDateTime.dateStrLong(): String =
"$day ${FRENCH_MONTHS[monthNumber - 1]} $year" "${FRENCH_DAYS[date.dayOfWeek.ordinal]} $day ${FRENCH_MONTHS[monthNumber - 1]} $year"
private fun LocalDateTime.timeStr(): String = private fun LocalDateTime.timeStr(): String =
if (minute == 0) "${hour}h" else "${hour}h${minute.toString().padStart(2, '0')}" if (minute == 0) "${hour}h" else "${hour}h${minute.toString().padStart(2, '0')}"
@@ -15,13 +15,13 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.viewmodel package ch.parano.myicek.viewmodel
import ch.parano.myice.auth.AuthSettings import ch.parano.myicek.auth.AuthSettings
import ch.parano.myice.auth.OAuthClient import ch.parano.myicek.auth.OAuthClient
import ch.parano.myice.network.ApiConfig import ch.parano.myicek.network.ApiConfig
import ch.parano.myice.network.ApiService import ch.parano.myicek.network.ApiService
import ch.parano.myice.network.AuthTokenHolder import ch.parano.myicek.network.AuthTokenHolder
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -15,10 +15,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.viewmodel package ch.parano.myicek.viewmodel
import ch.parano.myice.models.EventDetail import ch.parano.myicek.models.EventDetail
import ch.parano.myice.network.ApiService import ch.parano.myicek.network.ApiService
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -15,17 +15,17 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.viewmodel package ch.parano.myicek.viewmodel
import ch.parano.myice.auth.AuthSettings import ch.parano.myicek.auth.AuthSettings
import ch.parano.myice.cache.ScheduleCache import ch.parano.myicek.cache.ScheduleCache
import ch.parano.myice.filter.TypeFilter import ch.parano.myicek.filter.TypeFilter
import ch.parano.myice.filter.distinctAgegroups import ch.parano.myicek.filter.distinctAgegroups
import ch.parano.myice.filter.distinctSubgroups import ch.parano.myicek.filter.distinctSubgroups
import ch.parano.myice.filter.filterEvents import ch.parano.myicek.filter.filterEvents
import ch.parano.myice.models.Account import ch.parano.myicek.models.Account
import ch.parano.myice.models.Event import ch.parano.myicek.models.Event
import ch.parano.myice.network.ApiService import ch.parano.myicek.network.ApiService
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -15,9 +15,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.cache package ch.parano.myicek.cache
import ch.parano.myice.models.Event import ch.parano.myicek.models.Event
import com.russhwolf.settings.MapSettings import com.russhwolf.settings.MapSettings
import com.russhwolf.settings.Settings import com.russhwolf.settings.Settings
import kotlin.test.Test import kotlin.test.Test
@@ -15,9 +15,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.filter package ch.parano.myicek.filter
import ch.parano.myice.models.Event import ch.parano.myicek.models.Event
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.models package ch.parano.myicek.models
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlin.test.Test import kotlin.test.Test
@@ -15,9 +15,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.network package ch.parano.myicek.network
import ch.parano.myice.models.EventDetail import ch.parano.myicek.models.EventDetail
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.engine.mock.MockEngine import io.ktor.client.engine.mock.MockEngine
import io.ktor.client.engine.mock.respond import io.ktor.client.engine.mock.respond
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.util package ch.parano.myicek.util
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@@ -28,7 +28,7 @@ class EventDateTimeFormatterTest {
start = "2024-11-10T14:00:00", start = "2024-11-10T14:00:00",
end = "2024-11-10T16:15:00", end = "2024-11-10T16:15:00",
) )
assertEquals("10 novembre 2024 de 14h à 16h15", formatted) assertEquals("Dimanche 10 novembre 2024 de 14h à 16h15", formatted)
} }
@Test @Test
@@ -37,7 +37,7 @@ class EventDateTimeFormatterTest {
start = "2026-08-09 10:00:00", start = "2026-08-09 10:00:00",
end = "2026-08-09 12:00:00", end = "2026-08-09 12:00:00",
) )
assertEquals("9 août 2026 de 10h à 12h", formatted) assertEquals("Dimanche 9 août 2026 de 10h à 12h", formatted)
} }
@Test @Test
@@ -46,7 +46,7 @@ class EventDateTimeFormatterTest {
start = "2024-11-10T20:00:00", start = "2024-11-10T20:00:00",
end = "2024-11-11T01:30:00", end = "2024-11-11T01:30:00",
) )
assertEquals("10 novembre 2024 de 20h à 1h30 (11 novembre 2024)", formatted) assertEquals("Dimanche 10 novembre 2024 de 20h à 1h30 (Lundi 11 novembre 2024)", formatted)
} }
@Test @Test
@@ -66,4 +66,10 @@ class EventDateTimeFormatterTest {
val formatted = formatEventDateTime(start = "s", end = "e") val formatted = formatEventDateTime(start = "s", end = "e")
assertEquals("s - e", formatted) assertEquals("s - e", formatted)
} }
@Test
fun formatsEventDateWithDayOfWeek() {
val formatted = formatEventDate("2026-08-09T10:00:00")
assertEquals("Dimanche 9 août 2026", formatted)
}
} }
@@ -15,13 +15,13 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.viewmodel package ch.parano.myicek.viewmodel
import ch.parano.myice.cache.ScheduleCache import ch.parano.myicek.cache.ScheduleCache
import ch.parano.myice.filter.TypeFilter import ch.parano.myicek.filter.TypeFilter
import ch.parano.myice.models.Account import ch.parano.myicek.models.Account
import ch.parano.myice.models.Event import ch.parano.myicek.models.Event
import ch.parano.myice.network.ApiService import ch.parano.myicek.network.ApiService
import com.russhwolf.settings.MapSettings import com.russhwolf.settings.MapSettings
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.engine.mock.MockEngine import io.ktor.client.engine.mock.MockEngine
@@ -15,11 +15,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice package ch.parano.myicek
import androidx.compose.ui.window.Window import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application import androidx.compose.ui.window.application
import ch.parano.myice.auth.DesktopOAuthClient import ch.parano.myicek.auth.DesktopOAuthClient
fun main() = application { fun main() = application {
Window(onCloseRequest = ::exitApplication, title = "MyIceK") { Window(onCloseRequest = ::exitApplication, title = "MyIceK") {
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.auth package ch.parano.myicek.auth
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.network package ch.parano.myicek.network
import io.ktor.client.engine.HttpClientEngineConfig import io.ktor.client.engine.HttpClientEngineConfig
import io.ktor.client.engine.HttpClientEngineFactory import io.ktor.client.engine.HttpClientEngineFactory
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui package ch.parano.myicek.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -15,10 +15,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice package ch.parano.myicek
import androidx.compose.ui.window.ComposeUIViewController import androidx.compose.ui.window.ComposeUIViewController
import ch.parano.myice.auth.IosOAuthClient import ch.parano.myicek.auth.IosOAuthClient
fun MainViewController() = ComposeUIViewController { fun MainViewController() = ComposeUIViewController {
App(oauthClient = IosOAuthClient()) App(oauthClient = IosOAuthClient())
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.auth package ch.parano.myicek.auth
import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.network package ch.parano.myicek.network
import io.ktor.client.engine.HttpClientEngineConfig import io.ktor.client.engine.HttpClientEngineConfig
import io.ktor.client.engine.HttpClientEngineFactory import io.ktor.client.engine.HttpClientEngineFactory
@@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
package ch.parano.myice.ui package ch.parano.myicek.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
+1 -1
View File
@@ -61,7 +61,7 @@
<array> <array>
<dict> <dict>
<key>CFBundleURLName</key> <key>CFBundleURLName</key>
<string>ch.parano.myice</string> <string>ch.parano.myicek</string>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>myice</string> <string>myice</string>