Skip to content

Commit 6dd6157

Browse files
committed
Merge branch 'fix-develop' into develop
2 parents 627bd9d + 3d514b9 commit 6dd6157

39 files changed

Lines changed: 336 additions & 132 deletions

.github/workflows/nix-android.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Build APKs for Android using Nix
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
build:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v5
11+
with:
12+
fetch-depth: 0
13+
submodules: 'recursive'
14+
15+
- uses: cachix/install-nix-action@v31
16+
17+
- name: Check Necessary environment variables presence
18+
run: |
19+
if [ -z "$LOCAL_PROPERTIES" ] || [ -z "$GOOGLE_SERVICES_JSON" ]; then
20+
echo "You may want to add LOCAL_PROPERTIES and GOOGLE_SERVICES_JSON environment variables to your secrets"
21+
exit 1
22+
fi
23+
env:
24+
LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
25+
GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
26+
27+
- name: Build Task
28+
run: nix --experimental-features "nix-command flakes" run .#buildRelease
29+
env:
30+
LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
31+
GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }}
32+
33+
- name: Upload Release APKs
34+
uses: actions/upload-artifact@v7
35+
with:
36+
name: Release APKs
37+
path: app/build/outputs/apk/release/*.apk
38+

app/src/main/java/org/monogram/app/di/AppModule.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ val appModule = module {
4141
}
4242
single<Logger> { LoggerImpl() }
4343

44+
single<DateFormatManager> { DateFormatManagerImpl(androidContext()) }
45+
4446
factory<PhoneManager> {
4547
PhoneManagerImpl(
4648
androidContext().getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager,

flake.nix

Lines changed: 114 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,119 @@
11
{
2-
description = "Native Telegram client for Android based on TDLib.";
2+
description = "Native Telegram client for Android based on TDLib.";
33

4-
inputs = {
5-
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6-
flake-parts.url = "github:hercules-ci/flake-parts";
7-
systems.url = "github:nix-systems/default";
8-
};
4+
inputs = {
5+
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6+
flake-parts.url = "github:hercules-ci/flake-parts";
7+
systems.url = "github:nix-systems/default";
8+
};
9+
10+
outputs =
11+
inputs:
12+
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
13+
systems = import inputs.systems;
14+
15+
perSystem =
16+
{ pkgs, system, ... }:
17+
let
18+
actualBuildTools = "36.0.0";
19+
androidComposition =
20+
pkgs:
21+
(pkgs.androidenv.composeAndroidPackages {
22+
platformVersions = [
23+
"35"
24+
"36"
25+
];
26+
27+
buildToolsVersions = [
28+
"35.0.0"
29+
actualBuildTools
30+
];
31+
32+
cmakeVersions = [
33+
"3.22.1"
34+
];
35+
36+
ndkVersions = [
37+
"27.0.12077973"
38+
"28.2.13676358"
39+
];
40+
41+
abiVersions = [
42+
"armeabi-v7a"
43+
"arm64-v8a"
44+
"x86_64"
45+
];
46+
47+
systemImageTypes = [ "google_apis_playstore" ];
48+
includeNDK = true;
49+
includeCmake = true;
50+
includeSources = true;
51+
includeExtras = [ "extras;google;auto" ];
52+
}).androidsdk;
53+
in
54+
{
55+
_module.args.pkgs = import inputs.nixpkgs {
56+
inherit system;
57+
config = {
58+
android_sdk.accept_license = true;
59+
allowUnfree = true;
60+
};
61+
};
62+
63+
devShells.default = pkgs.mkShell {
64+
name = "monogram-sdk";
965

10-
outputs =
11-
inputs:
12-
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
13-
systems = import inputs.systems;
14-
15-
perSystem =
16-
{ pkgs, system, ... }:
17-
let
18-
androidComposition =
19-
pkgs:
20-
(pkgs.androidenv.composeAndroidPackages {
21-
platformVersions = [
22-
"35"
23-
"36"
24-
];
25-
26-
buildToolsVersions = [
27-
"35.0.0"
28-
];
29-
30-
cmakeVersions = [
31-
"3.22.1"
32-
];
33-
34-
ndkVersions = [
35-
"27.0.12077973"
36-
];
37-
38-
abiVersions = [
39-
"armeabi-v7a"
40-
"arm64-v8a"
41-
"x86_64"
42-
];
43-
44-
systemImageTypes = [ "google_apis_playstore" ];
45-
includeNDK = true;
46-
includeCmake = true;
47-
includeExtras = [ "extras;google;auto" ];
48-
}).androidsdk;
49-
in
50-
{
51-
_module.args.pkgs = import inputs.nixpkgs {
52-
inherit system;
53-
config = {
54-
android_sdk.accept_license = true;
55-
allowUnfree = true;
56-
};
57-
};
58-
59-
devShells.default =
60-
(pkgs.buildFHSEnv {
61-
name = "monogram-sdk-env";
62-
63-
targetPkgs = pkgs: [
64-
(androidComposition pkgs)
65-
pkgs.glibc
66-
pkgs.jdk21
67-
];
68-
69-
profile = ''
70-
export JAVA_HOME="/usr/lib/openjdk"
71-
export ANDROID_HOME="/usr/libexec/android-sdk"
72-
'';
73-
74-
runScript = "bash";
75-
}).env;
76-
};
66+
nativeBuildInputs = [
67+
(androidComposition pkgs)
68+
pkgs.glibc
69+
pkgs.jdk21
70+
pkgs.android-studio
71+
];
72+
73+
JAVA_HOME = "${pkgs.jdk21}";
74+
ANDROID_HOME = "${androidComposition pkgs}/libexec/android-sdk";
75+
};
76+
77+
apps = {
78+
buildRelease = {
79+
type = "app";
80+
program = "${pkgs.writeShellScriptBin "buildRelease" ''
81+
if [ -z "$LOCAL_PROPERTIES" ] || [ -z "$GOOGLE_SERVICES_JSON" ]; then
82+
echo "LOCAL_PROPERTIES and GOOGLE_SERVICES_JSON environment variables must be set"
83+
exit 1
84+
fi
85+
86+
if ! ${pkgs.git}/bin/git submodule update --init --recursive; then
87+
echo "failed getting submodules"
88+
fi
89+
90+
echo $LOCAL_PROPERTIES >local.properties
91+
echo $GOOGLE_SERVICES_JSON >app/google-services.json
92+
93+
export ANDROID_HOME="${androidComposition pkgs}/libexec/android-sdk/"
94+
export ANDROID_SDK_ROOT="${androidComposition pkgs}/libexec/android-sdk/"
95+
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk-bundle/"
96+
export GRADLE_OPTS="-Dorg.gradle.project.android.aapt2FromMavenOverride=${androidComposition pkgs}/libexec/android-sdk/build-tools/${actualBuildTools}/aapt2"
97+
export JAVA_HOME="${pkgs.jdk21}"
98+
99+
cd presentation/src/main/cpp/
100+
if ! [ -d libvpx_build ]; then
101+
sed -e "s|#!/bin/bash|#!${pkgs.bash}/bin/bash|g" \
102+
-e "s|make clean|${pkgs.gnumake}/bin/make clean|g" \
103+
-e "s|make -j|${pkgs.gnumake}/bin/make -j|g" build.sh >new_build.sh
104+
chmod +x new_build.sh
105+
if ! ${pkgs.bash}/bin/bash new_build.sh; then
106+
echo "libvpx build failed"
107+
exit 1
108+
fi
109+
rm new_build.sh
110+
fi
111+
112+
cd ../../../..
113+
./gradlew assembleRelease
114+
''}/bin/buildRelease";
115+
};
116+
};
77117
};
118+
};
78119
}

presentation/src/main/java/org/monogram/presentation/core/util/DateUtils.kt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package org.monogram.presentation.core.util
22

3+
import android.content.Context
4+
import android.text.format.DateFormat
5+
import androidx.compose.runtime.Composable
6+
import org.koin.compose.koinInject
37
import java.text.SimpleDateFormat
48
import java.util.Calendar
59
import java.util.Date
@@ -13,13 +17,17 @@ import kotlin.math.roundToLong
1317
* @param locale a [Locale] object which used with this date
1418
* @param now optional current date (for custom formatting or testing)
1519
**/
20+
@Composable
1621
fun Date.toShortRelativeDate(
1722
locale: Locale = Locale.getDefault(),
1823
now: Date = Date()
1924
): String {
2025
val currentCalendar = Calendar.getInstance(locale).apply { time = now }
2126
val targetCalendar = Calendar.getInstance(locale).apply { time = this@toShortRelativeDate }
2227

28+
val dateFormatManager: DateFormatManager = koinInject()
29+
val timeFormat = dateFormatManager.getHourMinuteFormat()
30+
2331
val currentDayStart = currentCalendar.clone() as Calendar
2432
currentDayStart.apply {
2533
set(Calendar.HOUR_OF_DAY, 0)
@@ -42,7 +50,7 @@ fun Date.toShortRelativeDate(
4250

4351
return when (diffDays) {
4452
0L -> {
45-
SimpleDateFormat("HH:mm", locale).format(this)
53+
SimpleDateFormat(timeFormat, locale).format(this)
4654
}
4755
in 1..6 -> {
4856
SimpleDateFormat("EEE", locale).format(this)
@@ -59,3 +67,13 @@ fun Date.toShortRelativeDate(
5967
}
6068
}
6169
}
70+
71+
interface DateFormatManager {
72+
fun is24HourFormat(): Boolean
73+
fun getHourMinuteFormat(): String
74+
}
75+
76+
class DateFormatManagerImpl(private val context: Context) : DateFormatManager {
77+
override fun is24HourFormat(): Boolean = DateFormat.is24HourFormat(context)
78+
override fun getHourMinuteFormat(): String = if (this.is24HourFormat()) "HH:mm" else "h:mm a"
79+
}

presentation/src/main/java/org/monogram/presentation/core/util/StringUtil.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ import androidx.compose.ui.text.font.FontStyle
1414
import androidx.compose.ui.text.font.FontWeight
1515
import androidx.compose.ui.text.style.TextDecoration
1616
import androidx.compose.ui.text.withStyle
17+
import org.koin.compose.koinInject
1718
import org.monogram.domain.models.*
1819
import org.monogram.presentation.R
1920
import java.text.SimpleDateFormat
2021
import java.util.*
2122

22-
fun formatLastSeen(lastSeen: Long?, context: Context): String {
23+
fun formatLastSeen(lastSeen: Long?, context: Context, timeFormat: String): String {
2324
if (lastSeen == null || lastSeen <= 0L) return context.getString(R.string.last_seen_recently)
2425

2526
val now = System.currentTimeMillis()
2627
val diff = now - lastSeen
27-
2828
if (diff < 0) return context.getString(R.string.last_seen_just_now)
2929

3030
return when {
@@ -35,12 +35,12 @@ fun formatLastSeen(lastSeen: Long?, context: Context): String {
3535
}
3636

3737
DateUtils.isToday(lastSeen) -> {
38-
val time = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date(lastSeen))
38+
val time = SimpleDateFormat(timeFormat, Locale.getDefault()).format(Date(lastSeen))
3939
context.getString(R.string.last_seen_at, time)
4040
}
4141

4242
isYesterday(lastSeen) -> {
43-
val time = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date(lastSeen))
43+
val time = SimpleDateFormat(timeFormat, Locale.getDefault()).format(Date(lastSeen))
4444
context.getString(R.string.last_seen_yesterday_at, time)
4545
}
4646

@@ -57,10 +57,12 @@ fun rememberUserStatusText(user: UserModel?): String {
5757
if (user.type == UserTypeEnum.BOT) return stringResource(R.string.status_bot)
5858

5959
val context = LocalContext.current
60+
val dateFormatManager: DateFormatManager = koinInject()
61+
val timeFormat = dateFormatManager.getHourMinuteFormat()
6062
return remember(user.userStatus, user.lastSeen) {
6163
when (user.userStatus) {
6264
UserStatusType.ONLINE -> context.getString(R.string.status_online)
63-
UserStatusType.OFFLINE -> formatLastSeen(user.lastSeen, context)
65+
UserStatusType.OFFLINE -> formatLastSeen(user.lastSeen, context, timeFormat)
6466
UserStatusType.RECENTLY -> context.getString(R.string.last_seen_recently)
6567
UserStatusType.LAST_WEEK -> context.getString(R.string.last_seen_within_week)
6668
UserStatusType.LAST_MONTH -> context.getString(R.string.last_seen_within_month)
@@ -73,13 +75,13 @@ private fun isYesterday(timestamp: Long): Boolean {
7375
return DateUtils.isToday(timestamp + DateUtils.DAY_IN_MILLIS)
7476
}
7577

76-
fun getUserStatusText(user: UserModel?, context: Context): String {
78+
fun getUserStatusText(user: UserModel?, context: Context, timeFormat: String): String {
7779
if (user == null) return context.getString(R.string.status_offline)
7880
if (user.type == UserTypeEnum.BOT) return context.getString(R.string.status_bot)
7981

8082
return when (user.userStatus) {
8183
UserStatusType.ONLINE -> context.getString(R.string.status_online)
82-
UserStatusType.OFFLINE -> formatLastSeen(user.lastSeen, context)
84+
UserStatusType.OFFLINE -> formatLastSeen(user.lastSeen, context, timeFormat)
8385
UserStatusType.RECENTLY -> context.getString(R.string.last_seen_recently)
8486
UserStatusType.LAST_WEEK -> context.getString(R.string.last_seen_within_week)
8587
UserStatusType.LAST_MONTH -> context.getString(R.string.last_seen_within_month)

presentation/src/main/java/org/monogram/presentation/features/chats/chatList/components/MessageSearchItem.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import androidx.compose.ui.Modifier
1010
import androidx.compose.ui.text.font.FontWeight
1111
import androidx.compose.ui.text.style.TextOverflow
1212
import androidx.compose.ui.unit.dp
13+
import org.koin.compose.koinInject
1314
import org.monogram.domain.models.MessageContent
1415
import org.monogram.domain.models.MessageModel
1516
import org.monogram.presentation.core.ui.Avatar
17+
import org.monogram.presentation.core.util.DateFormatManager
1618
import java.text.SimpleDateFormat
1719
import java.util.*
1820

@@ -27,11 +29,14 @@ fun MessageSearchItem(
2729
val currentCalendar = Calendar.getInstance()
2830
calendar.time = date
2931

32+
val dateFormatManager: DateFormatManager = koinInject();
33+
val timeFormat = dateFormatManager.getHourMinuteFormat()
34+
3035
val isToday = calendar.get(Calendar.YEAR) == currentCalendar.get(Calendar.YEAR) &&
3136
calendar.get(Calendar.DAY_OF_YEAR) == currentCalendar.get(Calendar.DAY_OF_YEAR)
3237

3338
val format = if (isToday) {
34-
SimpleDateFormat("HH:mm", Locale.getDefault())
39+
SimpleDateFormat(timeFormat, Locale.getDefault())
3540
} else {
3641
SimpleDateFormat("MMM d", Locale.getDefault())
3742
}

0 commit comments

Comments
 (0)