diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..d9f5985b38a1a7bed21654eb1178b3412c73106f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,30 @@ +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 + +[{*.mod, *.dtd, *.ent, *.elt}] +indent_style = space +indent_size = 2 + +[{*.jhm, *.rng, *.wsdl, *.fxml, *.xslt, *.jrxml, *.ant, *.xul, *.xsl, *.xsd, *.tld, *.jnlp, *.xml}] +indent_style = space +indent_size = 2 + +[*.json] +indent_style = space +indent_size = 2 + +[*.java] +indent_style = space +indent_size = 2 + +[{*.kts, *.kt}] +indent_style = space +indent_size = 2 + +[{*.yml, *.yaml}] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..49ca4c228ed79f9d56056083a5bfcf559e1cd597 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.iml +.gradle +/local.properties +/signing.properties +/.idea/* +!/.idea/copyright/ +.DS_Store +/captures +build/ +/reports/ +/persistence/schemas/ diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..baf04cf77c8afb388ff9a9a780ab13debda7b312 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,102 @@ +@file:Suppress("UnstableApiUsage") + +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Mareike Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +plugins { + id("justjanne.android.app") + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.kotlin.ksp) + alias(libs.plugins.dagger.hilt) +} + +android { + namespace = "de.justjanne.chatconcept" + + buildTypes { + getByName("release") { + + proguardFiles( + getDefaultProguardFile("proguard-android.txt"), + "proguard-rules.pro" + ) + signingConfig = signingConfigs.getByName("debug") + } + + getByName("debug") { + applicationIdSuffix = ".debug" + } + } + + buildFeatures { + compose = true + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() + } +} + +dependencies { + implementation(libs.kotlin.stdlib) + implementation(libs.kotlinx.datetime) + implementation(libs.kotlinx.serialization.json) + coreLibraryDesugaring(libs.desugar.jdk) + + implementation(libs.kotlinx.coroutines.android) + testImplementation(libs.kotlinx.coroutines.test) + + testImplementation(libs.kotlin.test) + testImplementation(libs.junit.api) + testImplementation(libs.junit.params) + testRuntimeOnly(libs.junit.engine) + + implementation(libs.androidx.appcompat) + implementation(libs.androidx.appcompat.resources) + + implementation(libs.androidx.activity) + implementation(libs.androidx.activity.compose) + + implementation(libs.androidx.compose.animation) + implementation(libs.androidx.compose.compiler) + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.compose.material) + implementation(libs.androidx.compose.material.icons) + implementation(libs.androidx.compose.runtime) + implementation(libs.androidx.compose.ui.tooling) + + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.room.ktx) + implementation(libs.androidx.room.paging) + + implementation(libs.androidx.navigation.compose) + + implementation(libs.okhttp) + implementation(libs.coil.compose) + + implementation(libs.hilt.navigation) + implementation(libs.hilt.android) + ksp(libs.hilt.compiler) + + implementation(libs.androidx.datastore.preferences) + + debugImplementation(libs.androidx.compose.ui.tooling) + implementation(libs.androidx.compose.ui.preview) + testImplementation(libs.androidx.compose.ui.test) +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..690a4be68db285dea8841626be81fa215a589a84 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,54 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/lib/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle.kts. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# The project is open source anyway, obfuscation is useless. +-dontobfuscate + +# remove unnecessary warnings +# Android HTTP Libs +-dontnote android.net.http.** +-dontnote org.apache.http.** +# Kotlin stuff +-dontnote kotlin.** +# Gson +-dontnote com.google.gson.** +# Dagger +-dontwarn com.google.errorprone.annotations.* +# Retrofit +-dontwarn retrofit2.** +# Annotation used by Retrofit on Java 8 VMs +-dontwarn javax.annotation.Nullable +-dontwarn javax.annotation.ParametersAreNonnullByDefault +-dontwarn javax.annotation.concurrent.GuardedBy +# Retain generic type information for use by reflection by converters and adapters. +-keepattributes Signature +# Retain declared checked exceptions for use by a Proxy instance. +-keepattributes Exceptions +# Okio +-dontwarn okio.** +-dontwarn org.conscrypt.** +# OkHttp3 +-dontwarn okhttp3.** diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..14ec190e23a483ba93c5726220241d9dfe0c6c72 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android"> + + <uses-permission android:name="android.permission.INTERNET" /> + + <application + android:name=".ChatConceptApplication" + android:allowBackup="true" + android:icon="@mipmap/ic_launcher" + android:label="@string/application_name" + android:supportsRtl="true" + android:theme="@style/Theme.ChatConcept"> + <activity + android:name=".MainActivity" + android:exported="true" + android:theme="@style/Theme.ChatConcept" + android:windowSoftInputMode="adjustResize"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <action android:name="android.intent.action.VIEW" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/app/src/main/kotlin/de/justjanne/chatconcept/ChatConceptApplication.kt b/app/src/main/kotlin/de/justjanne/chatconcept/ChatConceptApplication.kt new file mode 100644 index 0000000000000000000000000000000000000000..b26f8c340cfde0019ecea53cfdd07dad749497a8 --- /dev/null +++ b/app/src/main/kotlin/de/justjanne/chatconcept/ChatConceptApplication.kt @@ -0,0 +1,7 @@ +package de.justjanne.chatconcept + +import android.app.Application + +class ChatConceptApplication : Application() { + +} diff --git a/app/src/main/kotlin/de/justjanne/chatconcept/InputArea.kt b/app/src/main/kotlin/de/justjanne/chatconcept/InputArea.kt new file mode 100644 index 0000000000000000000000000000000000000000..f9a555f0d3363226f204dbed132d8c3cbb945d0e --- /dev/null +++ b/app/src/main/kotlin/de/justjanne/chatconcept/InputArea.kt @@ -0,0 +1,86 @@ +package de.justjanne.chatconcept + +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.Send +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + +@Composable +@Preview +fun InputArea(modifier: Modifier = Modifier) { + var input by remember { mutableStateOf("") } + val interactionSource = remember { MutableInteractionSource() } + + Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) { + BasicTextField( + value = input, + onValueChange = { input = it }, + modifier = Modifier + .weight(1.0f, true) + .fillMaxHeight(), + singleLine = false, + maxLines = 5, + minLines = 1, + enabled = true, + interactionSource = interactionSource, + ) { + OutlinedTextFieldDefaults.DecorationBox( + value = input, + visualTransformation = VisualTransformation.None, + innerTextField = it, + singleLine = false, + enabled = true, + placeholder = { Text("Send a meow message…") }, + interactionSource = interactionSource, + container = { + OutlinedTextFieldDefaults.ContainerBox( + enabled = true, + isError = false, + colors = OutlinedTextFieldDefaults.colors( + focusedBorderColor = Color.Transparent, + unfocusedBorderColor = Color.Transparent, + errorBorderColor = Color.Transparent, + disabledBorderColor = Color.Transparent, + ), + interactionSource = interactionSource, + shape = RectangleShape, + unfocusedBorderThickness = 0.dp, + focusedBorderThickness = 0.dp + ) + } + ) + } + IconButton( + onClick = { }, + Modifier + .padding(4.dp) + .align(Alignment.Top) + ) { + Icon( + Icons.AutoMirrored.Default.Send, + contentDescription = null, + tint = MaterialTheme.colorScheme.secondary + ) + } + } +} diff --git a/app/src/main/kotlin/de/justjanne/chatconcept/MainActivity.kt b/app/src/main/kotlin/de/justjanne/chatconcept/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..575ce058aca2e0f05de83797232b0ab5bea677a2 --- /dev/null +++ b/app/src/main/kotlin/de/justjanne/chatconcept/MainActivity.kt @@ -0,0 +1,266 @@ +package de.justjanne.chatconcept + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import coil.compose.rememberAsyncImagePainter +import de.justjanne.chatconcept.theme.ChatConceptTheme +import kotlinx.datetime.Instant + +data class User( + val id: String, + val displayName: String, + val avatarUrl: String, +) + +sealed class FileAttachment { + data class Image(val url: String) : FileAttachment() + data class Video(val url: String) : FileAttachment() + data class Audio(val url: String) : FileAttachment() + data class Generic(val url: String) : FileAttachment() +} + +sealed class Message { + data class TextMessage(val timestamp: Instant, val sender: User, val content: String) : Message() + data class Join(val timestamp: Instant, val sender: User) : Message() + data class Leave(val timestamp: Instant, val sender: User) : Message() + data class Kick(val timestamp: Instant, val sender: User, val subject: User) : Message() + data class AttachmentMessage( + val timestamp: Instant, + val sender: User, + val content: FileAttachment + ) : Message() +} + +data class RoomMember( + val user: User, + val powerLevel: Int, + val membership: Membership +) + +enum class Membership { + Joined, + Invited, + Banned +} + +sealed class Room { + data class GroupRoom( + val displayName: String, + val topic: String, + val avatarUrl: String, + val members: List<RoomMember>, + val timeline: Timeline, + ) : Room() + + data class DmRoom( + val user: User, + val members: List<RoomMember>, + val timeline: Timeline, + ) : Room() +} + +data class Timeline( + val messages: List<Message>, + val outbox: List<Message>, +) + +object SampleClient { + private val evelyn = User( + id = "@evelyn:eve.li", + displayName = "Evelyn", + avatarUrl = "https://avatars.githubusercontent.com/u/36997087?v=4" + ) + + private val janne = User( + id = "@justjanne:decentralised.chat", + displayName = "justJanne", + avatarUrl = "https://avatars.githubusercontent.com/u/3933349?v=4" + ) + + val rooms: List<Room> = listOf( + Room.DmRoom( + user = evelyn, + members = listOf( + RoomMember(evelyn, 100, Membership.Joined), + RoomMember(janne, 100, Membership.Joined), + ), + timeline = Timeline( + messages = listOf( + Message.TextMessage( + timestamp = Instant.parse("2023-11-16T17:06:54Z"), + sender = evelyn, + content = "meow!" + ), + Message.TextMessage( + timestamp = Instant.parse("2023-11-16T17:07:08Z"), + sender = evelyn, + content = "lust zu telefonieren? \uD83E\uDD7A" + ), + Message.TextMessage( + timestamp = Instant.parse("2023-11-16T17:07:12Z"), + sender = janne, + content = "miaaaauuu" + ), + Message.TextMessage( + timestamp = Instant.parse("2023-11-16T17:07:22Z"), + sender = evelyn, + content = "mag ui basteln \uD83E\uDD7A" + ), + Message.TextMessage( + timestamp = Instant.parse("2023-11-16T17:07:32Z"), + sender = janne, + content = "gerne, wie ist's in 2min?" + ), + Message.TextMessage( + timestamp = Instant.parse("2023-11-16T17:07:41Z"), + sender = evelyn, + content = "ja" + ), + ), + outbox = emptyList() + ) + ) + ) +} + +class SampleMessageProvider : PreviewParameterProvider<Message> { + override val values = (SampleClient.rooms[0] as Room.DmRoom).timeline.messages.asSequence() +} + +@Composable +@Preview(widthDp = 120, showBackground = true) +fun MessageView( + @PreviewParameter(SampleMessageProvider::class) + message: Message +) { + Row { + + Text("Hallo") + } +} + +@Composable +fun Avatar(name: String, imageUrl: String, modifier: Modifier = Modifier) { + val avatarPainter = rememberAsyncImagePainter(imageUrl) + + Box(modifier) { + Text( + name.first().toString(), + modifier = Modifier.align(Alignment.Center) + ) + Image( + avatarPainter, + contentDescription = null, + contentScale = ContentScale.Fit, + modifier = Modifier + .aspectRatio(1.0f) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primaryContainer) + ) + } +} + +@Composable +@Preview(showSystemUi = true) +fun ChatConceptApp() { + val room = SampleClient.rooms[0] as Room.DmRoom + + Scaffold( + topBar = { + TopAppBar( + title = { Text(room.user.displayName) }, + navigationIcon = { + Avatar( + room.user.displayName, + room.user.avatarUrl, + modifier = Modifier.size(48.dp) + ) + }, + modifier = Modifier.shadow(8.dp) + ) + } + ) { padding -> + Box { + Column { + LazyColumn( + contentPadding = padding, + modifier = Modifier + .background(Color.Blue) + .fillMaxSize() + ) { + items(room.timeline.messages) { message -> + MessageView(message) + } + } + Spacer(Modifier.height(64.dp)) + } + Surface( + modifier = Modifier + .height(240.dp) + .fillMaxWidth() + .align(Alignment.BottomCenter) + .offset(0.dp, 240.dp - 64.dp), + tonalElevation = 16.dp, + shadowElevation = 16.dp + ) { + Column(Modifier.fillMaxWidth()) { + + Surface( + color = MaterialTheme.colorScheme.onSurfaceVariant.copy(0.4f), + shape = MaterialTheme.shapes.extraLarge, + modifier = Modifier + .padding(top = 4.dp) + .align(Alignment.CenterHorizontally) + ) { + Box(Modifier.size(width = 32.dp, height = 4.dp)) + } + InputArea(Modifier.fillMaxSize()) + } + } + } + } +} + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ChatConceptTheme { + ChatConceptApp() + } + } + } +} diff --git a/app/src/main/kotlin/de/justjanne/chatconcept/theme/Color.kt b/app/src/main/kotlin/de/justjanne/chatconcept/theme/Color.kt new file mode 100644 index 0000000000000000000000000000000000000000..5b4b98c0f7dee7042f0d5fcf6a0455332127298e --- /dev/null +++ b/app/src/main/kotlin/de/justjanne/chatconcept/theme/Color.kt @@ -0,0 +1,11 @@ +package de.justjanne.chatconcept.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) diff --git a/app/src/main/kotlin/de/justjanne/chatconcept/theme/Theme.kt b/app/src/main/kotlin/de/justjanne/chatconcept/theme/Theme.kt new file mode 100644 index 0000000000000000000000000000000000000000..6398668eebccf4b95171eab55bf141a379c4a147 --- /dev/null +++ b/app/src/main/kotlin/de/justjanne/chatconcept/theme/Theme.kt @@ -0,0 +1,94 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013-2023 Chaosdorf e.V. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package de.justjanne.chatconcept.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun ChatConceptTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} diff --git a/app/src/main/kotlin/de/justjanne/chatconcept/theme/Type.kt b/app/src/main/kotlin/de/justjanne/chatconcept/theme/Type.kt new file mode 100644 index 0000000000000000000000000000000000000000..be1fa7a4aefbe7c079acbd77f2deb3926ad7b4f6 --- /dev/null +++ b/app/src/main/kotlin/de/justjanne/chatconcept/theme/Type.kt @@ -0,0 +1,34 @@ +package de.justjanne.chatconcept.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4b6c4512da56438e2b5145882b4e74cf572649f3 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..3212f661f259dbcb980dadfcdb05946da5e88940 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ The MIT License (MIT) + ~ + ~ Copyright (c) 2013-2023 Chaosdorf e.V. + ~ + ~ Permission is hereby granted, free of charge, to any person obtaining a copy + ~ of this software and associated documentation files (the "Software"), to deal + ~ in the Software without restriction, including without limitation the rights + ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + ~ copies of the Software, and to permit persons to whom the Software is + ~ furnished to do so, subject to the following conditions: + ~ + ~ The above copyright notice and this permission notice shall be included in + ~ all copies or substantial portions of the Software. + ~ + ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + ~ THE SOFTWARE. + --> + +<resources> + <string name="application_name">ChatConcept</string> +</resources> diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000000000000000000000000000000000000..895101c2a5379c9ab1bed01ae952ec707a284407 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <style name="Theme.ChatConcept" parent="Theme.Material.DayNight.NoActionBar"> + <item name="android:colorPrimary">#ff9800</item> + <item name="android:colorAccent">#3a3f44</item> + <item name="android:statusBarColor">@android:color/transparent</item> + <item name="android:navigationBarColor">@android:color/transparent</item> + <item name="android:dialogTheme">@style/Theme.DialogFullScreen</item> + </style> + + <style name="Theme.Material.DayNight.NoActionBar" parent="@android:style/Theme.Material.Light.NoActionBar" /> + + <style name="Theme.DialogFullScreen" parent="Theme.Material.DayNight.NoActionBar"> + <item name="android:windowMinWidthMajor">100%</item> + <item name="android:windowMinWidthMinor">100%</item> + </style> +</resources> diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..c2d0836b0754bedeed89b7086bb684a4bb9c94dd --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,16 @@ +group = "de.justjanne" + +buildscript { + repositories { + google() + mavenCentral() + } +} + +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.jvm) apply false + alias(libs.plugins.kotlin.serialization) apply false + alias(libs.plugins.kotlin.ksp) apply false + alias(libs.plugins.dagger.hilt) apply false +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000000000000000000000000000000000..de22634d32d2c6b737ec4a7481c65d653f5e0053 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,33 @@ +# Quasseldroid - Quassel client for Android +# +# Copyright (c) 2019 Janne Mareike Koschinski +# Copyright (c) 2019 The Quassel Project +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3 as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see <http://www.gnu.org/licenses/>. +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +#org.gradle.parallel=true +# Enable gradle build cache +#org.gradle.caching=true +# Enable AndroidX +android.useAndroidX=true diff --git a/gradle/convention/build.gradle.kts b/gradle/convention/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..5039b124e68adbd03fc09bf01043bef7cbe3e458 --- /dev/null +++ b/gradle/convention/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + `kotlin-dsl` +} + +repositories { + gradlePluginPortal() + mavenCentral() + google() +} + +dependencies { + compileOnly(libs.android.gradlePlugin) + compileOnly(libs.kotlin.gradlePlugin) +} + +gradlePlugin { + plugins { + register("androidApplication") { + id = "justjanne.android.app" + implementationClass = "AndroidApplicationConvention" + } + register("androidLibrary") { + id = "justjanne.android.library" + implementationClass = "AndroidLibraryConvention" + } + register("kotlinAndroid") { + id = "justjanne.kotlin.android" + implementationClass = "KotlinAndroidConvention" + } + register("kotlin") { + id = "justjanne.kotlin" + implementationClass = "KotlinConvention" + } + } +} + +configure<JavaPluginExtension> { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} diff --git a/gradle/convention/gradle.properties b/gradle/convention/gradle.properties new file mode 100644 index 0000000000000000000000000000000000000000..c6cd2a7e2f146d9ed89db0cb1f4de21ac673e9fd --- /dev/null +++ b/gradle/convention/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configureondemand=true diff --git a/gradle/convention/gradle/wrapper/gradle-wrapper.jar b/gradle/convention/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa Binary files /dev/null and b/gradle/convention/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/convention/gradle/wrapper/gradle-wrapper.properties b/gradle/convention/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..fb6d3d63b99d27ecd955b3e04b14c08a0c03ab39 --- /dev/null +++ b/gradle/convention/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionSha256Szm=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradle/convention/settings.gradle.kts b/gradle/convention/settings.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..1475431930d7052a7235f9527a9c4926f9013683 --- /dev/null +++ b/gradle/convention/settings.gradle.kts @@ -0,0 +1,13 @@ +rootProject.name = "convention" + +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } + versionCatalogs { + create("libs") { + from(files("../libs.versions.toml")) + } + } +} diff --git a/gradle/convention/src/main/kotlin/AndroidApplicationConvention.kt b/gradle/convention/src/main/kotlin/AndroidApplicationConvention.kt new file mode 100644 index 0000000000000000000000000000000000000000..a6a58c475dcc2b736963bf649aad2bbd940a4f26 --- /dev/null +++ b/gradle/convention/src/main/kotlin/AndroidApplicationConvention.kt @@ -0,0 +1,66 @@ +import com.android.build.api.dsl.ApplicationExtension +import org.gradle.api.JavaVersion +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import util.cmd +import util.properties +import java.util.Locale + +class AndroidApplicationConvention : Plugin<Project> { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("com.android.application") + apply("justjanne.kotlin.android") + } + + extensions.configure<ApplicationExtension> { + compileSdk = 34 + + defaultConfig { + minSdk = 21 + targetSdk = 34 + + applicationId = "${rootProject.group}.${rootProject.name.lowercase(Locale.ROOT)}" + versionCode = cmd("git", "rev-list", "--count", "HEAD")?.toIntOrNull() ?: 1 + versionName = cmd("git", "describe", "--always", "--tags", "HEAD") ?: "1.0.0" + + signingConfig = signingConfigs.findByName("default") + + setProperty("archivesBaseName", "${rootProject.name}-$versionName") + + // Disable test runner analytics + testInstrumentationRunnerArguments["disableAnalytics"] = "true" + } + + signingConfigs { + SigningData.of(project.rootProject.properties("signing.properties"))?.let { + create("default") { + storeFile = file(it.storeFile) + storePassword = it.storePassword + keyAlias = it.keyAlias + keyPassword = it.keyPassword + } + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + + isCoreLibraryDesugaringEnabled = true + } + + testOptions { + unitTests.isIncludeAndroidResources = true + } + + lint { + warningsAsErrors = true + lintConfig = file("../lint.xml") + } + } + } + } +} diff --git a/gradle/convention/src/main/kotlin/AndroidLibraryConvention.kt b/gradle/convention/src/main/kotlin/AndroidLibraryConvention.kt new file mode 100644 index 0000000000000000000000000000000000000000..ead4e60c0cec6ebd386f3b559a5210b89e8a51d2 --- /dev/null +++ b/gradle/convention/src/main/kotlin/AndroidLibraryConvention.kt @@ -0,0 +1,37 @@ +import com.android.build.api.dsl.LibraryExtension +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure + +class AndroidLibraryConvention : Plugin<Project> { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("com.android.library") + apply("justjanne.kotlin.android") + } + + extensions.configure<LibraryExtension> { + compileSdk = 34 + + defaultConfig { + minSdk = 21 + + consumerProguardFiles("proguard-rules.pro") + + // Disable test runner analytics + testInstrumentationRunnerArguments["disableAnalytics"] = "true" + } + + compileOptions { + isCoreLibraryDesugaringEnabled = true + } + + lint { + warningsAsErrors = true + lintConfig = file("../lint.xml") + } + } + } + } +} diff --git a/gradle/convention/src/main/kotlin/KotlinAndroidConvention.kt b/gradle/convention/src/main/kotlin/KotlinAndroidConvention.kt new file mode 100644 index 0000000000000000000000000000000000000000..dbbe81b8fa8dbe87369a75269b16f5c87be27a60 --- /dev/null +++ b/gradle/convention/src/main/kotlin/KotlinAndroidConvention.kt @@ -0,0 +1,46 @@ +import com.android.build.gradle.BaseExtension +import org.gradle.api.JavaVersion +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.api.tasks.testing.Test +import org.gradle.jvm.toolchain.JavaLanguageVersion +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.withType +import util.kotlinOptions + +@Suppress("UnstableApiUsage") +class KotlinAndroidConvention : Plugin<Project> { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("org.jetbrains.kotlin.android") + } + + extensions.configure<BaseExtension> { + kotlinOptions { + freeCompilerArgs = freeCompilerArgs + listOf( + "-opt-in=kotlin.RequiresOptIn", + // Enable experimental coroutines APIs, including Flow + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + "-opt-in=kotlinx.coroutines.FlowPreview", + "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", + "-opt-in=kotlin.ExperimentalUnsignedTypes", + ) + + jvmTarget = JavaVersion.VERSION_17.toString() + } + } + + tasks.withType<Test> { + useJUnitPlatform() + } + + configure<JavaPluginExtension> { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } + } + } + } +} diff --git a/gradle/convention/src/main/kotlin/KotlinConvention.kt b/gradle/convention/src/main/kotlin/KotlinConvention.kt new file mode 100644 index 0000000000000000000000000000000000000000..d99f88171db54cdf468239e7c182cf8221b3d722 --- /dev/null +++ b/gradle/convention/src/main/kotlin/KotlinConvention.kt @@ -0,0 +1,45 @@ +import org.gradle.api.JavaVersion +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.api.tasks.testing.Test +import org.gradle.jvm.toolchain.JavaLanguageVersion +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension +import org.jetbrains.kotlin.gradle.dsl.kotlinExtension + +class KotlinConvention : Plugin<Project> { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("org.jetbrains.kotlin.jvm") + } + + extensions.configure<KotlinJvmProjectExtension> { + compilerOptions.freeCompilerArgs.addAll( + "-opt-in=kotlin.RequiresOptIn", + // Enable experimental coroutines APIs, including Flow + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + "-opt-in=kotlinx.coroutines.FlowPreview", + "-opt-in=kotlin.Experimental", + "-opt-in=kotlin.ExperimentalUnsignedTypes", + ) + + compilerOptions.jvmTarget.set(JvmTarget.JVM_17) + } + + tasks.withType<Test> { + useJUnitPlatform() + } + + configure<JavaPluginExtension> { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } + } + } + } +} diff --git a/gradle/convention/src/main/kotlin/SigningData.kt b/gradle/convention/src/main/kotlin/SigningData.kt new file mode 100644 index 0000000000000000000000000000000000000000..606738eecbb111455e19e9b5d03d2eb1bcba617e --- /dev/null +++ b/gradle/convention/src/main/kotlin/SigningData.kt @@ -0,0 +1,21 @@ +import java.util.* + +data class SigningData( + val storeFile: String, + val storePassword: String, + val keyAlias: String, + val keyPassword: String +) { + companion object { + fun of(properties: Properties?): SigningData? { + if (properties == null) return null + + val storeFile = properties.getProperty("storeFile") ?: return null + val storePassword = properties.getProperty("storePassword") ?: return null + val keyAlias = properties.getProperty("keyAlias") ?: return null + val keyPassword = properties.getProperty("keyPassword") ?: return null + + return SigningData(storeFile, storePassword, keyAlias, keyPassword) + } + } +} diff --git a/gradle/convention/src/main/kotlin/util/BaseExtensionExtensions.kt b/gradle/convention/src/main/kotlin/util/BaseExtensionExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..667f8dac0c5f3e58641f887081bd7af00ca9b388 --- /dev/null +++ b/gradle/convention/src/main/kotlin/util/BaseExtensionExtensions.kt @@ -0,0 +1,8 @@ +package util + +import com.android.build.gradle.BaseExtension +import org.gradle.api.plugins.ExtensionAware +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions + +fun BaseExtension.kotlinOptions(configure: KotlinJvmOptions.() -> Unit): Unit = + (this as ExtensionAware).extensions.configure("kotlinOptions", configure) diff --git a/gradle/convention/src/main/kotlin/util/ProjectExtensions.kt b/gradle/convention/src/main/kotlin/util/ProjectExtensions.kt new file mode 100644 index 0000000000000000000000000000000000000000..9ab40febbebc72d5631e5771626939ccef16e4a9 --- /dev/null +++ b/gradle/convention/src/main/kotlin/util/ProjectExtensions.kt @@ -0,0 +1,26 @@ +package util + +import org.gradle.api.Project +import java.io.ByteArrayOutputStream +import java.util.Properties + +fun Project.cmd(vararg command: String) = try { + val stdOut = ByteArrayOutputStream() + exec { + commandLine(*command) + standardOutput = stdOut + } + stdOut.toString(Charsets.UTF_8.name()).trim() +} catch (e: Throwable) { + e.printStackTrace() + null +} + +fun Project.properties(fileName: String): Properties? { + val file = file(fileName) + if (!file.exists()) + return null + val props = Properties() + props.load(file.inputStream()) + return props +} diff --git a/gradle/init.gradle.kts b/gradle/init.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..7f161bac4f5349cc190dad7a4fa818f30d51da63 --- /dev/null +++ b/gradle/init.gradle.kts @@ -0,0 +1,55 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +val ktlintVersion = "0.48.1" + +initscript { + val spotlessVersion = "6.13.0" + + repositories { + mavenCentral() + } + + dependencies { + classpath("com.diffplug.spotless:spotless-plugin-gradle:$spotlessVersion") + } +} + +rootProject { + subprojects { + apply<com.diffplug.gradle.spotless.SpotlessPlugin>() + extensions.configure<com.diffplug.gradle.spotless.SpotlessExtension> { + kotlin { + target("**/*.kt") + targetExclude("**/build/**/*.kt") + ktlint(ktlintVersion).userData(mapOf("android" to "true")) + licenseHeaderFile(rootProject.file("gradle/spotless/copyright.kt")) + } + format("kts") { + target("**/*.kts") + targetExclude("**/build/**/*.kts") + // Look for the first line that doesn't have a block comment (assumed to be the license) + licenseHeaderFile(rootProject.file("gradle/spotless/copyright.kts"), "(^(?![\\/ ]\\*).*$)") + } + format("xml") { + target("**/*.xml") + targetExclude("**/build/**/*.xml") + // Look for the first XML tag that isn't a comment (<!--) or the xml declaration (<?xml) + licenseHeaderFile(rootProject.file("gradle/spotless/copyright.xml"), "(<[^!?])") + } + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000000000000000000000000000000000000..7d17d98c36153e3781bde380b0437745f8e56180 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,92 @@ +[versions] +androidGradlePlugin = "8.1.3" +androidx-activity = "1.8.0" +androidx-appcompat = "1.6.1" +androidx-compose-bom = "2023.10.01" +androidx-compose-compiler = "1.5.4" +androidx-compose-material = "1.5.0-alpha04" +androidx-compose-material3 = "1.2.0-alpha10" +androidx-compose-runtimetracing = "1.0.0-alpha04" +androidx-compose-tooling = "1.6.0-alpha08" +androidx-datastore = "1.0.0" +androidx-hilt = "1.1.0" +androidx-navigation = "2.7.5" +androidx-room = "2.6.0" +coil = "2.4.0" +dagger-hilt = "2.48.1" +desugar-jdk = "2.0.4" +kotlin = "1.9.20" +kotlin-ksp = "1.9.20-1.0.14" +kotlinxCoroutines = "1.7.1" +kotlinxDatetime = "0.4.0" +kotlinxSerializationJson = "1.5.1" +junit = "5.10.0" + +[libraries] +androidx-activity = { module = "androidx.activity:activity-ktx", version.ref = "androidx-activity" } +androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" } + +androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } +androidx-appcompat-resources = { module = "androidx.appcompat:appcompat-resources", version.ref = "androidx-appcompat" } + +androidx-compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "androidx-compose-compiler" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidx-compose-bom" } +androidx-compose-animation = { group = "androidx.compose.animation", name = "animation" } +androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" } +androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout" } +androidx-compose-material-icons = { group = "androidx.compose.material", name = "material-icons-extended", version = "1.6.0-alpha08" } +androidx-compose-material = { group = "androidx.compose.material3", name = "material3", version.ref = "androidx-compose-material3" } +androidx-compose-material-windowSizeClass = { group = "androidx.compose.material3", name = "material3-window-size-class", version.ref = "androidx-compose-material3" } +androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" } +androidx-compose-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata" } +androidx-compose-runtime-tracing = { group = "androidx.compose.runtime", name = "runtime-tracing", version.ref = "androidx-compose-runtimetracing" } +androidx-compose-ui-test = { group = "androidx.compose.ui", name = "ui-test" } +androidx-compose-ui-testManifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "androidx-compose-tooling" } +androidx-compose-ui-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "androidx-compose-tooling" } +androidx-compose-ui-util = { group = "androidx.compose.ui", name = "ui-util" } + +androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" } + +androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidx-room" } +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx-room" } +androidx-room-paging = { module = "androidx.room:room-paging", version.ref = "androidx-room" } + +coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" } + +hilt-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "dagger-hilt" } +hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "dagger-hilt" } +hilt-navigation = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "androidx-hilt" } +okhttp = { module = "com.squareup.okhttp3:okhttp", version = "4.12.0" } +retrofit-core = { module = "com.squareup.retrofit2:retrofit", version = "2.9.0" } +retrofit-converter-kotlinx = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version = "1.0.0" } + +androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidx-navigation" } + +junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" } +junit-params = { group = "org.junit.jupiter", name = "junit-jupiter-params", version.ref = "junit" } +junit-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine" } + +kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" } +kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test-junit5", version.ref = "kotlin" } +kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } +kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } +kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } +kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } + +desugar-jdk = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar-jdk" } + +# Dependencies of the included build-logic +android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } +kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } +android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } +android-test = { id = "com.android.test", version.ref = "androidGradlePlugin" } +dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "dagger-hilt" } +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "kotlin.ksp" } diff --git a/gradle/spotless/copyright.kt b/gradle/spotless/copyright.kt new file mode 100644 index 0000000000000000000000000000000000000000..cc357e57ccfd48837c7436bd410605601f2200c4 --- /dev/null +++ b/gradle/spotless/copyright.kt @@ -0,0 +1,23 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013-$YEAR Chaosdorf e.V. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/gradle/spotless/copyright.kts b/gradle/spotless/copyright.kts new file mode 100644 index 0000000000000000000000000000000000000000..cc357e57ccfd48837c7436bd410605601f2200c4 --- /dev/null +++ b/gradle/spotless/copyright.kts @@ -0,0 +1,23 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013-$YEAR Chaosdorf e.V. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/gradle/spotless/copyright.xml b/gradle/spotless/copyright.xml new file mode 100644 index 0000000000000000000000000000000000000000..6c59cbaeeab079c0254e5cc4df972b333efa8204 --- /dev/null +++ b/gradle/spotless/copyright.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + The MIT License (MIT) + + Copyright (c) 2013-$YEAR Chaosdorf e.V. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +--> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7f93135c49b765f8051ef9d0a6055ff8e46073d8 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..3fa8f862f753336d4fabfd607678a7a2317e8a06 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000000000000000000000000000000000..1aa94a4269074199e6ed2c37e8db3e0826030965 --- /dev/null +++ b/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000000000000000000000000000000000..6689b85beecde676054c39c2408085f41e6be6dc --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lint.xml b/lint.xml new file mode 100644 index 0000000000000000000000000000000000000000..eab67bd5e6f29d10e42082945d8a9195c76e4777 --- /dev/null +++ b/lint.xml @@ -0,0 +1,53 @@ +<!-- + Quasseldroid - Quassel client for Android + + Copyright (c) 2019 Janne Mareike Koschinski + Copyright (c) 2019 The Quassel Project + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License version 3 as published + by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see <http://www.gnu.org/licenses/>. + --> + +<lint> + <issue id="NewerVersionAvailable" severity="error" /> + + <!-- Because of course paging and room have incompatible versions --> + <issue id="GradleCompatible" severity="ignore" /> + + <!-- Because these are entirely broken --> + <issue id="ResourceType" severity="ignore" /> + <issue id="UnusedResources" severity="ignore" /> + <issue id="ObsoleteLintCustomCheck" severity="ignore" /> + <issue id="UnusedAttribute" severity="informational" /> + + <!-- Because this doesn’t work when using splash themes --> + <issue id="Overdraw" severity="ignore" /> + + <!-- Can’t request a translation without a release, can’t release without translation --> + <issue id="MissingTranslation" severity="informational" /> + <!-- Because we don’t use app bundles and never will use them --> + <issue id="AppBundleLocaleChanges" severity="informational" /> + <!-- Because this tries to apply english orthography to other locales --> + <issue id="Typos" severity="ignore" /> + + <!-- Because Autofill isn’t a priority at the moment --> + <issue id="Autofill" severity="informational" /> + + <!-- We’re not using AGP 5 yet, and once we are, we’ll use compose anyway --> + <issue id="NonConstantResourceId" severity="informational" /> + + <!-- It’s only used for testing --> + <issue id="TrustAllX509TrustManager" severity="informational" /> + + <!-- TODO for the future --> + <issue id="DataExtractionRules" severity="informational" /> +</lint> diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..e77b474c1407546ab8b7898fbfedfd615be124ad --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013-2023 Chaosdorf e.V. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +rootProject.name = "chatconcept" + +pluginManagement { + includeBuild("gradle/convention") + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +include(":app")