Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
275 changes: 275 additions & 0 deletions app/src/androidTest/java/com/nmc/android/AlbumsResourceTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.nmc.android

import android.content.Context
import android.content.res.Configuration
import android.util.DisplayMetrics
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.owncloud.android.R
import junit.framework.TestCase.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import java.util.Locale

/**
* Test class to verify the strings and dimens customized in this branch PR for NMC
*/
@RunWith(AndroidJUnit4::class)
class AlbumsResourceTest {

private val baseContext = ApplicationProvider.getApplicationContext<Context>()

private val localizedStringMap = mapOf(
R.string.drawer_item_album to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Albums",
Locale.GERMAN to "Alben"
)
), R.string.create_album to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Create album",
Locale.GERMAN to "Album erstellen"
)
), R.string.create_album_dialog_title to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "New album",
Locale.GERMAN to "Neues Album"
)
), R.string.rename_album_dialog_title to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Rename album",
Locale.GERMAN to "Album umbenennen"
)
), R.string.rename_dialog_button to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Rename",
Locale.GERMAN to "Speichern"
)
), R.string.create_album_dialog_message to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Enter your new Album name",
Locale.GERMAN to "Gib einen Namen für das Album ein"
)
), R.string.album_name_empty to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Album name cannot be empty",
Locale.GERMAN to "Der Albumname darf nicht leer sein"
)
), R.string.add_more to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Add more",
Locale.GERMAN to "Mehr hinzufügen"
)
), R.string.album_rename to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Rename Album",
Locale.GERMAN to "Album umbenennen"
)
), R.string.album_delete to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Delete Album",
Locale.GERMAN to "Album löschen"
)
), R.string.album_delete_failed_message to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Failed to delete few of the files.",
Locale.GERMAN to "Einige Dateien konnten nicht gelöscht werden."
)
), R.string.album_already_exists to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Album already exists",
Locale.GERMAN to "Das Album existiert bereits"
)
), R.string.album_picker_toolbar_title to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Pick Album",
Locale.GERMAN to "Album auswählen"
)
), R.string.media_picker_toolbar_title to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Pick Media Files",
Locale.GERMAN to "Mediendateien auswählen"
)
), R.string.empty_albums_title to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Create Albums for your Photos",
Locale.GERMAN to "Erstelle Alben für deine Fotos"
)
), R.string.empty_albums_message to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "You can organize all your photos in as many albums as you like. You haven\'t created an album yet.",
Locale.GERMAN to "Sie können all Ihre Fotos in beliebig vielen Alben organisieren. Bisher haben Sie noch kein Album erstellt."
)
), R.string.add_to_album to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Add to album",
Locale.GERMAN to "Zum Album hinzufügen"
)
), R.string.album_file_added_message to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "File added successfully",
Locale.GERMAN to "Datei erfolgreich hinzugefügt"
)
), R.string.empty_album_detailed_view_title to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "All that\'s missing are your photos",
Locale.GERMAN to "Es fehlen nur noch Ihre Fotos"
)
), R.string.empty_album_detailed_view_message to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "You can add as many photos as you like. A photo can also belong to more than one album.",
Locale.GERMAN to "Sie können so viele Fotos hinzufügen, wie Sie möchten. Ein Foto kann auch mehreren Alben zugeordnet werden."
)
), R.string.add_photos to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Add photos",
Locale.GERMAN to "Fotos hinzufügen"
)
), R.string.album_unsupported_file to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Unsupported media",
Locale.GERMAN to "Nicht unterstützte Medien"
)
), R.string.album_upload_from_camera_roll to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Upload from cameraroll",
Locale.GERMAN to "Dateien hochladen"
)
), R.string.album_upload_from_account to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Select images from account",
Locale.GERMAN to "Dateien auswählen"
)
), R.string.album_rename_conflict to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "This name is already in use.",
Locale.GERMAN to "Dieser Name wird bereits verwendet."
)
), R.string.album_copy_file_conflict to ExpectedLocalizedString(
translations = mapOf(
Locale.ENGLISH to "Already exists.",
Locale.GERMAN to "Existiert bereits."
)
),
)

@Test
fun verifyLocalizedStrings() {
localizedStringMap.forEach { (stringRes, expected) ->
expected.translations.forEach { (locale, expectedText) ->

val config = Configuration(baseContext.resources.configuration)
config.setLocale(locale)

val localizedContext = baseContext.createConfigurationContext(config)
val actualText = localizedContext.getString(stringRes)

assertEquals(
"Mismatch for ${baseContext.resources.getResourceEntryName(stringRes)} in $locale",
expectedText,
actualText
)
}
}
}

data class ExpectedLocalizedString(val translations: Map<Locale, String>)

private val expectedDimenMap = mapOf(
R.dimen.album_list_image_width to ExpectedDimen(
default = 78f,
unit = DimenUnit.DP
),
R.dimen.album_list_image_height to ExpectedDimen(
default = 56f,
unit = DimenUnit.DP
),
R.dimen.album_grid_image_height to ExpectedDimen(
default = 140f,
unit = DimenUnit.DP
),
R.dimen.album_grid_image_corner_radius to ExpectedDimen(
default = 8f,
unit = DimenUnit.DP
),
R.dimen.album_list_image_corner_radius to ExpectedDimen(
default = 4f,
unit = DimenUnit.DP
),
R.dimen.album_grid_spacing to ExpectedDimen(
default = 4f,
unit = DimenUnit.DP
),
R.dimen.album_recycler_view_grid_padding to ExpectedDimen(
default = 8f,
unit = DimenUnit.DP
),
)

@Test
fun validateDefaultDimens() {
validateDimens(
configModifier = { it }, // no change → default values
) { it.default to it.unit }
}

@Test
fun validate_sw600dp_Dimens() {
validateDimens(configModifier = { config ->
config.smallestScreenWidthDp = 600
config
}) { it.alt to it.unit }
}

private fun validateDimens(
configModifier: (Configuration) -> Configuration,
selector: (ExpectedDimen) -> Pair<Float?, DimenUnit>
) {
val baseConfig = Configuration(baseContext.resources.configuration)
val testConfig = configModifier(baseConfig)
val testContext = baseContext.createConfigurationContext(testConfig)
val dm = testContext.resources.displayMetrics
val config = testContext.resources.configuration
expectedDimenMap.forEach { (resId, entry) ->
val (value, unit) = selector(entry)
val actualPx = testContext.resources.getDimension(resId)
value?.let {
val expectedPx = convertToPx(value, unit, dm, config)
assertEquals(
"Mismatch for ${testContext.resources.getResourceEntryName(resId)} ($unit)",
expectedPx,
actualPx,
0.01f
)
}
}
}

private fun convertToPx(
value: Float,
unit: DimenUnit,
dm: DisplayMetrics,
config: Configuration
): Float {
return when (unit) {
DimenUnit.DP -> value * dm.density
DimenUnit.SP -> value * dm.density * config.fontScale
DimenUnit.PX -> value
}
}

data class ExpectedDimen(
val default: Float,
val alt: Float? = null,
val unit: DimenUnit,
)

enum class DimenUnit { DP, SP, PX }
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
import com.nextcloud.client.widget.DashboardWidgetService;
import com.nextcloud.ui.ChooseAccountDialogFragment;
import com.nextcloud.ui.ChooseStorageLocationDialogFragment;
import com.nextcloud.ui.fileInfo.FileInfoFragment;
import com.nextcloud.ui.SetOnlineStatusBottomSheet;
import com.nextcloud.ui.SetStatusMessageBottomSheet;
import com.nextcloud.ui.albumItemActions.AlbumItemActionsBottomSheet;
import com.nextcloud.ui.composeActivity.ComposeActivity;
import com.nextcloud.ui.fileInfo.FileInfoFragment;
import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
import com.nextcloud.ui.tags.TagManagementBottomSheet;
import com.nextcloud.ui.trashbinFileActions.TrashbinFileActionsBottomSheet;
Expand Down Expand Up @@ -110,17 +110,17 @@
import com.owncloud.android.ui.fragment.GalleryFragment;
import com.owncloud.android.ui.fragment.GalleryFragmentBottomSheetDialog;
import com.owncloud.android.ui.fragment.GroupfolderListFragment;
import com.owncloud.android.ui.fragment.localfilelist.LocalFileListFragment;
import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog;
import com.owncloud.android.ui.fragment.OCFileListFragment;
import com.owncloud.android.ui.fragment.SharedListFragment;
import com.owncloud.android.ui.fragment.UnifiedSearchFragment;
import com.owncloud.android.ui.fragment.albums.AlbumItemsFragment;
import com.owncloud.android.ui.fragment.albums.bottomsheet.AlbumSharingBottomSheet;
import com.owncloud.android.ui.fragment.albums.AlbumsFragment;
import com.owncloud.android.ui.fragment.albums.bottomsheet.AlbumSharingBottomSheet;
import com.owncloud.android.ui.fragment.community.CommunityFragment;
import com.owncloud.android.ui.fragment.contactsbackup.BackupFragment;
import com.owncloud.android.ui.fragment.contactsbackup.BackupListFragment;
import com.owncloud.android.ui.fragment.localfilelist.LocalFileListFragment;
import com.owncloud.android.ui.fragment.notifications.NotificationsFragment;
import com.owncloud.android.ui.navigation.NavigatorActivity;
import com.owncloud.android.ui.preview.FileDownloadFragment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class BackgroundJobFactory @Inject constructor(
FileUploadWorker::class -> createFilesUploadWorker(context, workerParameters)
AlbumFileUploadWorker::class -> createAlbumsFilesUploadWorker(context, workerParameters)
FileDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters)
AlbumFileUploadWorker::class -> createAlbumsFilesUploadWorker(context, workerParameters)
GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters)
HealthStatusWork::class -> createHealthStatusWork(context, workerParameters)
TestJob::class -> createTestJob(context, workerParameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,11 @@ class FileUploadHelper {

@Suppress("ReturnCount")
fun isUploadingNow(upload: OCUpload?): Boolean {
val currentUploadFileOperation = FileUploadWorker.getCurrentUpload(upload?.uploadId)
var currentUploadFileOperation = FileUploadWorker.getCurrentUpload(upload?.uploadId)
// NMC Customization: to check for Files uploaded through albums
if (currentUploadFileOperation == null) {
currentUploadFileOperation = AlbumFileUploadWorker.getCurrentUpload(upload?.uploadId)
}
if (currentUploadFileOperation == null || currentUploadFileOperation.user == null) return false
if (upload == null || upload.accountName != currentUploadFileOperation.user.accountName) return false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@

package com.nextcloud.ui.albumItemActions

import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
import androidx.annotation.StringRes
import com.owncloud.android.R

enum class AlbumItemAction(val id: Int, val titleId: Int, val iconId: Int) {
UPLOAD_FROM_CAMERA_ROLL(
R.id.action_upload_from_camera_roll,
R.string.upload_direct_camera_upload,
R.drawable.ic_camera
),
SELECT_IMAGES_FROM_ACCOUNT(
R.id.action_select_images_from_account,
R.string.album_upload_from_account,
R.drawable.file_image
);
enum class AlbumItemAction(@IdRes val id: Int, @StringRes val title: Int, @DrawableRes val icon: Int? = null) {
RENAME_ALBUM(R.id.action_rename_album, R.string.album_rename, R.drawable.ic_edit),
SHARE_ALBUM(R.id.action_share_album, R.string.album_share, R.drawable.ic_share),
DELETE_ALBUM(R.id.action_delete_album, R.string.album_delete, R.drawable.ic_delete);

companion object {
/**
* All file actions, in the order they should be displayed
*/
@JvmField
val SORTED_VALUES = listOf(
UPLOAD_FROM_CAMERA_ROLL,
SELECT_IMAGES_FROM_ACCOUNT
RENAME_ALBUM,
SHARE_ALBUM,
DELETE_ALBUM
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ class AlbumItemActionsBottomSheet :
val bottomSheetDialog = dialog as BottomSheetDialog
bottomSheetDialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
bottomSheetDialog.behavior.skipCollapsed = true

viewThemeUtils.platform.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE)

return binding.root
}

Expand Down Expand Up @@ -96,13 +93,10 @@ class AlbumItemActionsBottomSheet :
root.setOnClickListener {
dispatchActionClick(action.id)
}
text.setText(action.titleId)
val drawable =
viewThemeUtils.platform.tintDrawable(
requireContext(),
AppCompatResources.getDrawable(requireContext(), action.iconId)!!
)
icon.setImageDrawable(drawable)
text.setText(action.title)
if (action.icon != null) {
icon.setImageResource(action.icon)
}
}
return itemBinding.root
}
Expand Down
Loading