mirror of
https://github.com/fromchat-messenger/app.git
synced 2026-09-22 19:15:05 +03:00
@@ -17,3 +17,6 @@ build
|
|||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
.cxx
|
.cxx
|
||||||
local.properties
|
local.properties
|
||||||
|
|
||||||
|
keys
|
||||||
|
releases
|
||||||
+24
-2
@@ -1,4 +1,7 @@
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.util.Properties
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
@@ -27,10 +30,29 @@ android {
|
|||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
create("release") {
|
||||||
|
val keystoreProperties = Properties().apply {
|
||||||
|
load(FileInputStream(rootProject.file("keys/keystore.properties")))
|
||||||
|
}
|
||||||
|
storeFile = rootProject.file("keys/release.jks")
|
||||||
|
keyAlias = "release"
|
||||||
|
storePassword = keystoreProperties["storePassword"].toString()
|
||||||
|
keyPassword = keystoreProperties["keyPassword"].toString()
|
||||||
|
enableV3Signing = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
isMinifyEnabled = false
|
isMinifyEnabled = true
|
||||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
isShrinkResources = true
|
||||||
|
signingConfig = signingConfigs.getByName("release")
|
||||||
|
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,19 +9,16 @@
|
|||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:theme="@style/Theme.FromChat">
|
||||||
android:theme="@style/Theme.FromChat"
|
|
||||||
android:usesCleartextTraffic="true">
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/Theme.FromChat">
|
android:theme="@style/Theme.FromChat"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.fromchat.api
|
package ru.fromchat.api
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
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.plugins.contentnegotiation.ContentNegotiation
|
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||||
@@ -54,7 +55,7 @@ object ApiClient {
|
|||||||
http
|
http
|
||||||
.post("https://fromchat.ru/api/login") {
|
.post("https://fromchat.ru/api/login") {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
setBody(request)
|
setBody(request.also { Log.d("ApiClient", "Login request: $it") })
|
||||||
}
|
}
|
||||||
.failOnError()
|
.failOnError()
|
||||||
.body<LoginResponse>()
|
.body<LoginResponse>()
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package ru.fromchat.ui.auth
|
package ru.fromchat.ui.auth
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.Login
|
import androidx.compose.material.icons.automirrored.filled.Login
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@@ -34,7 +37,7 @@ fun LoginScreen(
|
|||||||
onLoginSuccess: () -> Unit,
|
onLoginSuccess: () -> Unit,
|
||||||
onNavigateToRegister: () -> Unit
|
onNavigateToRegister: () -> Unit
|
||||||
) {
|
) {
|
||||||
Scaffold { innerPadding ->
|
Scaffold(contentWindowInsets = WindowInsets.safeDrawing) { innerPadding ->
|
||||||
var username by remember { mutableStateOf("") }
|
var username by remember { mutableStateOf("") }
|
||||||
var password by remember { mutableStateOf("") }
|
var password by remember { mutableStateOf("") }
|
||||||
var alert by remember { mutableStateOf<String?>(null) }
|
var alert by remember { mutableStateOf<String?>(null) }
|
||||||
@@ -44,13 +47,14 @@ fun LoginScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(innerPadding)
|
.padding(innerPadding),
|
||||||
.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
@@ -89,13 +93,12 @@ fun LoginScreen(
|
|||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
apiRequest(
|
apiRequest(
|
||||||
onError = { message, e ->
|
onError = { message, _ ->
|
||||||
Log.e("LoginScreen", "An error ocurred while logging in:", e)
|
|
||||||
alert = message
|
alert = message
|
||||||
},
|
},
|
||||||
onSuccess = { onLoginSuccess() }
|
onSuccess = { onLoginSuccess() }
|
||||||
) {
|
) {
|
||||||
ApiClient.login(LoginRequest(username, password))
|
ApiClient.login(LoginRequest(username.trim(), password.trim()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,19 @@ package ru.fromchat.ui.auth
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.PersonAdd
|
import androidx.compose.material.icons.filled.PersonAdd
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
@@ -26,30 +34,33 @@ import kotlinx.coroutines.launch
|
|||||||
import ru.fromchat.api.ApiClient
|
import ru.fromchat.api.ApiClient
|
||||||
import ru.fromchat.api.RegisterRequest
|
import ru.fromchat.api.RegisterRequest
|
||||||
import ru.fromchat.api.apiRequest
|
import ru.fromchat.api.apiRequest
|
||||||
|
import ru.fromchat.ui.LocalNavController
|
||||||
import ru.fromchat.ui.RowHeader
|
import ru.fromchat.ui.RowHeader
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RegisterScreen(
|
fun RegisterScreen(
|
||||||
onRegistered: () -> Unit
|
onRegistered: () -> Unit
|
||||||
) {
|
) {
|
||||||
Scaffold { innerPadding ->
|
Scaffold(contentWindowInsets = WindowInsets.safeDrawing) { innerPadding ->
|
||||||
var username by remember { mutableStateOf("") }
|
var username by remember { mutableStateOf("") }
|
||||||
var password by remember { mutableStateOf("") }
|
var password by remember { mutableStateOf("") }
|
||||||
var confirmPassword by remember { mutableStateOf("") }
|
var confirmPassword by remember { mutableStateOf("") }
|
||||||
var alert by remember { mutableStateOf<String?>(null) }
|
var alert by remember { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(innerPadding)
|
.padding(innerPadding),
|
||||||
.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
@@ -86,6 +97,16 @@ fun RegisterScreen(
|
|||||||
visualTransformation = PasswordVisualTransformation()
|
visualTransformation = PasswordVisualTransformation()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FlowRow(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||||
|
IconButton(
|
||||||
|
onClick = { navController.navigateUp() }
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
|
contentDescription = "Back"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
// Checks
|
// Checks
|
||||||
@@ -132,3 +153,4 @@ fun RegisterScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Executable
+46
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 1. Setup
|
||||||
|
set -e
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
# 2. Variables
|
||||||
|
TAG=$(git describe --tags --abbrev=0)
|
||||||
|
# shellcheck disable=SC2207
|
||||||
|
TAGS=($(git --no-pager tag --sort -v:refname | xargs))
|
||||||
|
PREVTAG=${TAGS[1]}
|
||||||
|
ASSET_PATH=./app/build/outputs/apk/release/app-release.apk
|
||||||
|
DISPLAY_NAME=FromChat.$TAG.apk
|
||||||
|
|
||||||
|
# 3. Build release variant
|
||||||
|
./gradlew assembleRelease
|
||||||
|
|
||||||
|
# 4. Move locally
|
||||||
|
mkdir -p releases
|
||||||
|
mv "$ASSET_PATH" "releases/$DISPLAY_NAME"
|
||||||
|
ASSET_PATH=./releases/$DISPLAY_NAME
|
||||||
|
|
||||||
|
# 6. Release to GitHub
|
||||||
|
prerelease_opt=$([[ "$TAG" != v*-pre* ]] || echo "--prerelease")
|
||||||
|
|
||||||
|
new_release() {
|
||||||
|
gh release create \
|
||||||
|
"$TAG" \
|
||||||
|
--generate-notes \
|
||||||
|
--notes-start-tag "$PREVTAG" \
|
||||||
|
"$prerelease_opt" \
|
||||||
|
"$ASSET_PATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
edit_existing() {
|
||||||
|
gh release edit \
|
||||||
|
"$TAG" \
|
||||||
|
"$prerelease_opt"
|
||||||
|
gh release upload \
|
||||||
|
"$TAG" \
|
||||||
|
--clobber \
|
||||||
|
"$ASSET_PATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
git push --tags
|
||||||
|
new_release || edit_existing
|
||||||
Reference in New Issue
Block a user