Compare commits

..

1 Commits

Author SHA1 Message Date
Sylvia van Os
864bdbbe0b Revert "Temporarily re-add Android 5 support (#2925)"
This reverts commit 37e6782032.
2026-01-03 19:59:35 +01:00
29 changed files with 72 additions and 219 deletions

View File

@@ -50,10 +50,10 @@ jobs:
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Run instrumented tests (API 21)
- name: Run instrumented tests (API 23)
uses: ReactiveCircus/android-emulator-runner@v2
with:
api-level: 21
api-level: 23
arch: x86_64
script: ./gradlew connected${{ matrix.flavor }}DebugAndroidTest
- name: Run instrumented tests (API 35)

View File

@@ -1,20 +1,8 @@
# Changelog
## Unreleased - 162
## Unreleased - 159
- Fix list widget sometimes opening wrong card
- Fix About activity not using pure black title bar in OLED mode
## v2.41.4 - 161 (2026-01-04)
- Disable automatic barcode encoding detection for now (breaks too many cards)
## v2.41.3 - 160 (2026-01-04)
- Follow-up for fix in 2.41.2 for cards explicitly set to ISO-8859-1
- Migrate old cards to ISO-8859-1 to fix sudden behaviour differences for existing cards
## v2.41.2 - 159 (2026-01-03)
Android 5.0 and 5.1 are no longer supported starting with this release. If you want to use Catima on these versions, please use version 2.41.1.
- Fix change introduced in 2.41.0 that broke support for some scanners for non-UTF-8 barcodes

View File

@@ -17,10 +17,10 @@ android {
defaultConfig {
applicationId = "me.hackerchick.catima"
minSdk = 21
minSdk = 23
targetSdk = 36
versionCode = 161
versionName = "2.41.4"
versionCode = 158
versionName = "2.41.1"
vectorDrawables.useSupportLibrary = true
multiDexEnabled = true

View File

@@ -21,7 +21,6 @@ import com.google.zxing.common.StringUtils;
import java.lang.ref.WeakReference;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
@@ -185,44 +184,23 @@ public class BarcodeImageWriterTask implements CompatCallable<Bitmap> {
MultiFormatWriter writer = new MultiFormatWriter();
Map<EncodeHintType, Object> encodeHints = new ArrayMap<>();
Charset chosenEncoding = encoding;
// Use charset if defined or guess otherwise
if (chosenEncoding != null) {
Log.d(TAG, "Encoding explicitly set, " + chosenEncoding.name());
if (encoding != null) {
Log.d(TAG, "Encoding explicitly set, " + encoding.name());
encodeHints.put(EncodeHintType.CHARACTER_SET, encoding);
} else {
// FIXME: Guessing encoding using zxing causes too many false positives and breaks the Deutschlandticket, a common public transport ticket in Germany
// See https://github.com/CatimaLoyalty/Android/issues/2932
//
// So, for now, we just force ISO in the "guessing" path until we figure out a better way to guess
// The previous code is commented before, DO NOT UNCOMMENT, IT IS BROKEN
//
// chosenEncoding = Charset.forName(StringUtils.guessEncoding(cardId.getBytes(), new ArrayMap<>()));
// Log.d(TAG, "Guessed encoding: " + chosenEncoding.name());
String guessedEncoding = StringUtils.guessEncoding(cardId.getBytes(), new ArrayMap<>());
Log.d(TAG, "Guessed encoding: " + guessedEncoding);
// FIXME: Figure out a good way to automatically determine the best format to use, to not break UTF-8 barcodes
// However, make sure to NOT break the Deutschlandticket!
chosenEncoding = StandardCharsets.ISO_8859_1;
Log.w(TAG, "The encoding guessing code path is temporarily disabled due to it breaking Deutschlandticket. Forcing ISO-8859-1...");
}
// We don't want to pass the ISO-8859-1 as an encoding hint as zxing may add this as ECI
// inside the barcode.
//
// Due to many barcode scanners in the wild being badly coded they may trip over ECI
// info existing and fail to scan.
// See:
// - https://github.com/CatimaLoyalty/Android/issues/2921
// - https://github.com/CatimaLoyalty/Android/issues/2932
//
// Just not always passing the encoding hint is slightly hacky, but in 5+ years of Catima
// cards without encode hints have never caused any issues (unless they were UTF-8), yet
// just days after passing ISO-8859-1 as CHARACTER_SET in the encode hints already 2
// scan failures were reported (one for QR, one for Aztec).
if (!Objects.equals(chosenEncoding.name(), StandardCharsets.ISO_8859_1.name())) {
Log.d(TAG, "Chosen encoding is not ISO_8859_1, so passing as encoding hint");
encodeHints.put(EncodeHintType.CHARACTER_SET, chosenEncoding);
} else {
Log.d(TAG, "Not passing encoding as encoding hint");
// We don't want to pass the guessed encoding as an encoding hint unless it is UTF-8 as
// zxing is likely to add the mentioned encoding hint as ECI inside the barcode.
//
// Due to many barcode scanners in the wild being badly coded they may trip over ECI
// info existing and fail to scan, such as in https://github.com/CatimaLoyalty/Android/issues/2921
if (Objects.equals(guessedEncoding, "UTF8")) {
Log.d(TAG, "Guessed encoding is UTF8, so passing as encoding hint");
encodeHints.put(EncodeHintType.CHARACTER_SET, Charset.forName(guessedEncoding));
}
}
BitMatrix bitMatrix;

View File

@@ -38,15 +38,10 @@ public class CatimaAppCompatActivity extends AppCompatActivity {
Window window = getWindow();
if (window != null) {
boolean darkMode = Utils.isDarkModeEnabled(this);
if (Build.VERSION.SDK_INT >= 23) {
View decorView = window.getDecorView();
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(window, decorView);
wic.setAppearanceLightStatusBars(!darkMode);
window.setStatusBarColor(Color.TRANSPARENT);
} else {
// icons are always white back then
window.setStatusBarColor(darkMode ? Color.TRANSPARENT : Color.argb(127, 0, 0, 0));
}
View decorView = window.getDecorView();
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(window, decorView);
wic.setAppearanceLightStatusBars(!darkMode);
window.setStatusBarColor(Color.TRANSPARENT);
}
// XXX android 9 and below has a nasty rendering bug if the theme was patched earlier
Utils.postPatchColors(this);
@@ -66,7 +61,4 @@ public class CatimaAppCompatActivity extends AppCompatActivity {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
public void onMockedRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
}
}

View File

@@ -26,7 +26,7 @@ import java.util.Set;
public class DBHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "Catima.db";
public static final int ORIGINAL_DATABASE_VERSION = 1;
public static final int DATABASE_VERSION = 19;
public static final int DATABASE_VERSION = 18;
// NB: changing these values requires a migration
public static final int DEFAULT_ZOOM_LEVEL = 100;
@@ -345,17 +345,6 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
+ " ADD COLUMN " + LoyaltyCardDbIds.BARCODE_ENCODING + " TEXT");
}
// On upgrade to 2.41.3, force all existing "Automatic" cards to ISO-8859-1.
// UTF-8 support was only added in 2.42.0, before that, all barcodes were saved without
// any encoding info. As many scanners deal badly with ECI info, automatically guessing
// UTF-8 for old barcodes may break them.
//
// New cards will be saved using either "Automatic" encoding to guess or, for pkpass files,
// whatever encoding is specified.
if (oldVersion < 19 && newVersion >= 19) {
db.execSQL("UPDATE " + LoyaltyCardDbIds.TABLE + " SET " + LoyaltyCardDbIds.BARCODE_ENCODING + " = 'ISO-8859-1' WHERE " + LoyaltyCardDbIds.BARCODE_ENCODING + " IS NULL");
}
}
public static Set<String> imageFiles(Context context, final SQLiteDatabase database) {

View File

@@ -69,9 +69,7 @@ class ListWidget : AppWidgetProvider() {
if (hasCards) {
// If we have cards, create the list
views = RemoteViews(context.packageName, R.layout.list_widget)
val templateIntent = Intent(context, LoyaltyCardViewActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val templateIntent = Intent(context, LoyaltyCardViewActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
context,
0,
@@ -102,8 +100,7 @@ class ListWidget : AppWidgetProvider() {
val foreground = if (Utils.needsDarkForeground(headerColor)) Color.BLACK else Color.WHITE
setInt(R.id.item_container_foreground, "setBackgroundColor", headerColor)
val icon = loyaltyCard.getImageThumbnail(context)
// setImageViewIcon is not supported on Android 5, so force Android 5 down the text path
// FIXME: The icon flow causes a crash up to Android 12L, so SDK_INT is forced up from 23 to 33
// FIXME: The icon flow causes a crash up to Android 12L, so force anything below 33 down this path
if (icon != null && Build.VERSION.SDK_INT >= 32) {
setInt(R.id.item_container_foreground, "setBackgroundColor", foreground)
setImageViewIcon(R.id.item_image, Icon.createWithBitmap(icon))

View File

@@ -34,11 +34,6 @@ public class PermissionUtils {
* @return
*/
public static boolean needsCameraPermission(Activity activity) {
// Android only introduced the runtime permission system in Marshmallow (Android 6.0)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return false;
}
return ContextCompat.checkSelfPermission(activity, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED;
}
@@ -49,21 +44,14 @@ public class PermissionUtils {
* @param activity
* @param requestCode
*/
public static void requestStorageReadPermission(CatimaAppCompatActivity activity, int requestCode) {
public static void requestStorageReadPermission(Activity activity, int requestCode) {
String[] permissions = new String[]{ android.Manifest.permission.READ_EXTERNAL_STORAGE };
int[] mockedResults = new int[]{ PackageManager.PERMISSION_GRANTED };
if (needsStorageReadPermission(activity)) {
ActivityCompat.requestPermissions(activity, permissions, requestCode);
} else {
// FIXME: This points to onMockedRequestPermissionResult instead of to
// onRequestPermissionResult because onRequestPermissionResult was only introduced in
// Android 6.0 (SDK 23) and we and to support Android 5.0 (SDK 21) too.
//
// When minSdk becomes 23, this should point to onRequestPermissionResult directly and
// the activity input variable should be changed from CatimaAppCompatActivity to
// Activity.
activity.onMockedRequestPermissionsResult(requestCode, permissions, mockedResults);
activity.onRequestPermissionsResult(requestCode, permissions, mockedResults);
}
}
@@ -74,21 +62,14 @@ public class PermissionUtils {
* @param activity
* @param requestCode
*/
public static void requestCameraPermission(CatimaAppCompatActivity activity, int requestCode) {
public static void requestCameraPermission(Activity activity, int requestCode) {
String[] permissions = new String[]{ Manifest.permission.CAMERA };
int[] mockedResults = new int[]{ PackageManager.PERMISSION_GRANTED };
if (needsCameraPermission(activity)) {
ActivityCompat.requestPermissions(activity, permissions, requestCode);
} else {
// FIXME: This points to onMockedRequestPermissionResult instead of to
// onRequestPermissionResult because onRequestPermissionResult was only introduced in
// Android 6.0 (SDK 23) and we and to support Android 5.0 (SDK 21) too.
//
// When minSdk becomes 23, this should point to onRequestPermissionResult directly and
// the activity input variable should be changed from CatimaAppCompatActivity to
// Activity.
activity.onMockedRequestPermissionsResult(requestCode, permissions, mockedResults);
activity.onRequestPermissionsResult(requestCode, permissions, mockedResults);
}
}
}

View File

@@ -543,14 +543,6 @@ class ScanActivity : CatimaAppCompatActivity() {
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
onMockedRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onMockedRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
val granted =
grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED

View File

@@ -40,16 +40,9 @@ class UCropWrapper : UCropActivity() {
return
}
if (Build.VERSION.SDK_INT >= 23) {
val decorView = window.decorView
val wic = WindowInsetsControllerCompat(window, decorView)
wic.isAppearanceLightStatusBars = !darkMode
} else if (!darkMode) {
window.statusBarColor = ColorUtils.compositeColors(
Color.argb(127, 0, 0, 0),
window.statusBarColor
)
}
val decorView = window.decorView
val wic = WindowInsetsControllerCompat(window, decorView)
wic.isAppearanceLightStatusBars = !darkMode
}
private fun checkViews(darkMode: Boolean) {

View File

@@ -1,8 +1,6 @@
package protect.card_locker.compose
import androidx.activity.OnBackPressedDispatcher
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -10,38 +8,18 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import protect.card_locker.R
import protect.card_locker.preferences.Settings
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CatimaTopAppBar(title: String, onBackPressedDispatcher: OnBackPressedDispatcher?) {
// Use pure black in OLED theme
val context = LocalContext.current
val settings = Settings(context)
val isDarkMode = when (settings.theme) {
AppCompatDelegate.MODE_NIGHT_NO -> false
AppCompatDelegate.MODE_NIGHT_YES -> true
else -> isSystemInDarkTheme()
}
val appBarColors = if (isDarkMode && settings.oledDark) {
TopAppBarDefaults.topAppBarColors().copy(containerColor = Color.Black)
} else {
TopAppBarDefaults.topAppBarColors()
}
TopAppBar(
modifier = Modifier.testTag("topbar_catima"),
title = { Text(text = title) },
colors = appBarColors,
navigationIcon = {
if (onBackPressedDispatcher != null) {
IconButton(onClick = { onBackPressedDispatcher.onBackPressed() }) {

View File

@@ -77,13 +77,6 @@ public class CardsContentProvider extends ContentProvider {
@Nullable final String selection,
@Nullable final String[] selectionArgs,
@Nullable final String sortOrder) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Disable the content provider on SDK < 23 since it grants dangerous
// permissions at install-time
Log.w(TAG, "Content provider read is only available for SDK >= 23");
return null;
}
final Settings settings = new Settings(getContext());
if (!settings.getAllowContentProviderRead()) {
Log.w(TAG, "Content provider read is disabled");

View File

@@ -459,11 +459,9 @@ public class CatimaImporter implements Importer {
barcodeType = CatimaBarcode.fromName(unparsedBarcodeType);
}
// Barcode encoding information is only supported since Catima 2.41.0, so old exports will lack this field
// Database migration 19 forcing ISO-8859-1 on all cards, so we should treat imports from old Catima versions the same and force ISO-8859-1 there too
// This limits the risk of breaking cards when importing an old database backup
// This field did not exist in version 2.40.0 and before
Charset barcodeEncoding = null;
String unparsedBarcodeEncoding = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BARCODE_ENCODING, record, "ISO-8859-1");
String unparsedBarcodeEncoding = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BARCODE_ENCODING, record, "");
if (!unparsedBarcodeEncoding.isEmpty()) {
barcodeEncoding = Charset.forName(unparsedBarcodeEncoding);
}

View File

@@ -157,12 +157,6 @@ class SettingsActivity : CatimaAppCompatActivity() {
true
}
// Disable content provider on SDK < 23 since dangerous permissions
// are granted at install-time
val contentProviderReadPreference = findPreference<Preference>(getString(R.string.settings_key_allow_content_provider_read))
contentProviderReadPreference!!.isVisible =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
// Hide crash reporter settings on builds it's not enabled on
val crashReporterPreference = findPreference<Preference>("acra.enable")
crashReporterPreference!!.isVisible = BuildConfig.useAcraCrashReporter

View File

@@ -7,8 +7,8 @@ Heimen Stoffels
Oğuz Ersen
FC (Fay) Stegerman
StoyanDimitrov
B o d o
大王叫我来巡山
B o d o
SlavekB
Katharine Chui
mondstern
@@ -18,12 +18,12 @@ Altonss
Edgars Andersons
Joel A
Michael Moroni
Priit Jõerüüt
Liner Seven
Priit Jõerüüt
Eric
Fjuro
Максим Горпиніч
GitSpoon
Fjuro
GM
Petr Novák
laralem
@@ -33,14 +33,14 @@ pfaffenrodt
Aayush Gupta
Scrambled777
josé m
Vasilis
ikanakova
Nyatsuki
ikanakova
Vasilis
Kachelkaiser
Giovanni Donisi
Milo Ivir
HudobniVolk
Горпиніч Максим Олександрович
HudobniVolk
Jiri Grönroos
Warder
Samantaz Fox
@@ -48,19 +48,18 @@ Balázs Meskó
109247019824
Feike Donia
Arno-github
Ankit Tiwari
Cliff Heraldo
Sergio Paredes
Ankit Tiwari
Jose Delvani
mdvhimself
Milan Šalka
AMIR-G98
Robin
Milan Šalka
mdvhimself
தமிழ்நேரம்
huuhaa
Skrripy
Govindgopalyadav
damjang
Skrripy
huuhaa
waffshappen
Marnick L'Eau
ngocanhtve
@@ -68,18 +67,19 @@ aradxxx
StellarSand
Quentin PAGÈS
Projjal Moitra
Aliaksandr Trush
e-michalak
JungHee Lee
AMIR-G98
hajertabbane
inavleb
Ziad OUALHADJ
Robin Liu
Ricky Tigg
Renko
Gideon
Traductor
Aliaksandr Trush
Denis Shilin
Traductor
Gideon
Renko
Ricky Tigg
Robin Liu
しいたけ
Alexander Ivanov
Miha Frangež
@@ -88,14 +88,13 @@ mrestivill
ehrt74
Virginie
Tim Trek
Peter Dave Hello
Alì Mortacci
MisterCosta96
arshbeerSingh
Augustin LAVILLE
Freddo espresso
Vasudev R.
vasudev-cell
Kim Seohyun
rudy3
Michael Gangolf
PRATHAMESH BHAGAT
Peter Dave Hello

View File

@@ -299,7 +299,4 @@
<string name="copy_value">Копиране на стойността</string>
<string name="copied_to_clipboard">Копирано</string>
<string name="nothing_to_copy">Няма стойност</string>
<string name="back">Назад</string>
<string name="automatic">Автоматично</string>
<string name="barcodeEncoding">Кодиране на щрихкода</string>
</resources>

View File

@@ -305,7 +305,4 @@
<string name="copy_value">Kopírovat hodnotu</string>
<string name="copied_to_clipboard">Zkopírováno do schránky</string>
<string name="nothing_to_copy">Nenalezena žádná hodnota</string>
<string name="barcodeEncoding">Kódování čárového kódu</string>
<string name="automatic">Automatické</string>
<string name="back">Zpět</string>
</resources>

View File

@@ -100,7 +100,7 @@
<string name="importLoyaltyCardKeychain">Aus Loyalty Card Keychain importieren</string>
<string name="importFidmeMessage">Wähle deinen „FidMe-Export“ zum Importieren und anschließend manuell die Barcodetypen aus.\nErstelle ihn aus deinem FidMe-Profil, indem du Datenschutz wählst und dann auf Meine Daten extrahieren drückst.</string>
<string name="importFidme">Aus FidMe importieren</string>
<string name="importCatimaMessage">Wähle deinen „Catima-Export“ zum Importieren aus.\nExportiere diesen zuvor im Import/Export-Menü einer anderen Catima-Anwendung.</string>
<string name="importCatimaMessage">Wähle deinen „Catima-Export“ zum Importieren aus.\nErstelle diesen durch das Drücken auf Export im Import/Export-Menü in einer anderen Catima-Anwendung.</string>
<string name="importCatima">Aus Catima importieren</string>
<string name="setBarcodeId">Barcodewert festlegen</string>
<string name="sameAsCardId">Entspricht Kartennummer</string>

View File

@@ -10,7 +10,7 @@
<string name="edit">Editar</string>
<string name="delete">Eliminar</string>
<string name="confirm">Confirmar</string>
<string name="ok">Aceptar</string>
<string name="ok">De acuerdo</string>
<string name="sendLabel">Enviar…</string>
<string name="editCardTitle">Editar tarjeta</string>
<string name="addCardTitle">Añadir tarjeta</string>
@@ -134,7 +134,7 @@
<item quantity="many"><xliff:g>%d</xliff:g> seleccionadas</item>
<item quantity="other"><xliff:g>%d</xliff:g> seleccionadas</item>
</plurals>
<string name="deleteTitle">Eliminar tarjeta</string>
<string name="deleteTitle">Eliminar la tarjeta</string>
<string name="deleteConfirmation">¿Quiere eliminar permanentemente esta tarjeta\?</string>
<plurals name="deleteCardsConfirmation">
<item quantity="one">¿Borrar esta tarjeta <xliff:g>%d</xliff:g> permanentemente\?</item>
@@ -305,7 +305,4 @@
<string name="copy_value">Copia valor</string>
<string name="copied_to_clipboard">Copiado al portapapeles</string>
<string name="nothing_to_copy">Ningún valor encontrado</string>
<string name="barcodeEncoding">Codificación de barra de código</string>
<string name="automatic">Automático</string>
<string name="back">Atrás</string>
</resources>

View File

@@ -145,7 +145,7 @@
<string name="privacy_policy">Privātuma politika</string>
<string name="accept">Pieņemt</string>
<string name="editGroup">Kopas labošana: <xliff:g>%s</xliff:g></string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Autortiesības © 2019<xliff:g>%d</xliff:g> Sylvia van Os un līdzdalībnieki</string>
<string name="app_copyright_fmt" tools:ignore="PluralsCandidate">Autortiesības © 2019<xliff:g>%d</xliff:g> Sylvia van Os</string>
<string name="app_copyright_old">Balstīta uz Loyalty Card Keychain
\nautortiesības © 20162020 Branden Archer</string>
<string name="debug_version_fmt">Versija: <xliff:g id="version">%s</xliff:g></string>

View File

@@ -497,7 +497,7 @@ public class DatabaseTest {
assertEquals("cardId", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(BarcodeFormat.UPC_A, card.barcodeType.format());
assertEquals(StandardCharsets.ISO_8859_1, card.barcodeEncoding); // Old cards are assumed to be ISO-8859-1
assertEquals(null, card.barcodeEncoding);
assertEquals(null, card.headerColor);
assertEquals(0, card.starStatus);
assertEquals(0, card.lastUsed);
@@ -515,7 +515,7 @@ public class DatabaseTest {
assertEquals("cardId", card2.cardId);
assertEquals(null, card2.barcodeId);
assertEquals(null, card2.barcodeType); // Empty string should've become null
assertEquals(StandardCharsets.ISO_8859_1, card.barcodeEncoding); // Old cards are assumed to be ISO-8859-1
assertEquals(null, card.barcodeEncoding);
assertEquals(null, card2.headerColor);
assertEquals(0, card2.starStatus);
assertEquals(0, card2.lastUsed);

View File

@@ -669,7 +669,7 @@ public class ImportExportTest {
assertEquals("12345", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(BarcodeFormat.AZTEC, card.barcodeType.format());
assertEquals(StandardCharsets.ISO_8859_1, card.barcodeEncoding); // Old cards are assumed to be ISO-8859-1
assertEquals(null, card.barcodeEncoding);
assertNull(card.headerColor);
assertEquals(0, card.starStatus);
@@ -696,7 +696,7 @@ public class ImportExportTest {
assertEquals("12345", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(BarcodeFormat.AZTEC, card.barcodeType.format());
assertEquals(StandardCharsets.ISO_8859_1, card.barcodeEncoding); // Old cards are assumed to be ISO-8859-1
assertEquals(null, card.barcodeEncoding);
assertNull(card.headerColor);
assertEquals(0, card.starStatus);
@@ -735,7 +735,7 @@ public class ImportExportTest {
assertEquals("12345", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(null, card.barcodeType);
assertEquals(StandardCharsets.ISO_8859_1, card.barcodeEncoding); // Old cards are assumed to be ISO-8859-1
assertEquals(null, card.barcodeEncoding);
assertEquals(1, (long) card.headerColor);
assertEquals(0, card.starStatus);
@@ -762,7 +762,7 @@ public class ImportExportTest {
assertEquals("12345", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(BarcodeFormat.AZTEC, card.barcodeType.format());
assertEquals(StandardCharsets.ISO_8859_1, card.barcodeEncoding); // Old cards are assumed to be ISO-8859-1
assertEquals(null, card.barcodeEncoding);
assertEquals(1, (long) card.headerColor);
assertEquals(1, card.starStatus);
@@ -789,7 +789,7 @@ public class ImportExportTest {
assertEquals("12345", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(BarcodeFormat.AZTEC, card.barcodeType.format());
assertEquals(StandardCharsets.ISO_8859_1, card.barcodeEncoding); // Old cards are assumed to be ISO-8859-1
assertEquals(null, card.barcodeEncoding);
assertEquals(1, (long) card.headerColor);
assertEquals(0, card.starStatus);
@@ -823,7 +823,7 @@ public class ImportExportTest {
assertEquals("12345", card.cardId);
assertEquals(null, card.barcodeId);
assertEquals(BarcodeFormat.AZTEC, card.barcodeType.format());
assertEquals(StandardCharsets.ISO_8859_1, card.barcodeEncoding); // Old cards are assumed to be ISO-8859-1
assertEquals(null, card.barcodeEncoding);
assertEquals(1, (long) card.headerColor);
assertEquals(0, card.starStatus);

View File

@@ -3,4 +3,4 @@
- Einstellung für die Spaltenanzahl funktioniert nun auch in der Kartenansicht für Gruppen
- Unterstützung für Designfarben entfernt
- Maximale Fotogröße reduziert, um Speicherplatz zu sparen (gilt nur für neu hinzugefügte Fotos)
- About Activity von Android XML zu Jetpack Compose migriert
- AboutActivity von Android XML zu Jetpack Compose migriert

View File

@@ -1,2 +0,0 @@
- Follow-up for fix in 2.41.2 for cards explicitly set to ISO-8859-1
- Migrate old cards to ISO-8859-1 to fix sudden behaviour differences for existing cards

View File

@@ -1 +0,0 @@
- Disable automatic barcode encoding detection for now (breaks too many cards)

View File

@@ -1,2 +0,0 @@
- Fix list widget sometimes opening wrong card
- Fix About activity not using pure black title bar in OLED mode

View File

@@ -1,2 +0,0 @@
- Nowy projekt logo Catima
- Aktualizacja tłumaczeń

View File

@@ -1,3 +0,0 @@
- Dodanie wsparcia dla plików .pkpasses
- Usunięcie importera Stocard (Stocard już nie istnieje)
- Tymczasowe wyłączenie widżetów dla Androida poniżej 12L (obejście problemu awarii)

View File

@@ -1,6 +1,6 @@
[versions]
# AndroidX
compose = "2025.11.01"
compose = "2025.12.01"
# Third-party
acra = "5.13.1"
@@ -22,7 +22,7 @@ com-google-android-material-material = { group = "com.google.android.material",
com-android-tools-desugar_jdk_libs = { group = "com.android.tools", name = "desugar_jdk_libs", version = "2.1.5" }
# Compose
androidx-activity-activity-compose = { group = "androidx.activity", name = "activity-compose", version = "1.10.1" }
androidx-activity-activity-compose = { group = "androidx.activity", name = "activity-compose", version = "1.12.2" }
androidx-compose-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose" }
androidx-compose-foundation-foundation = { group = "androidx.compose.foundation", name = "foundation" }
androidx-compose-material3-material3 = { group = "androidx.compose.material3", name = "material3"}