diff --git a/app/build.gradle b/app/build.gradle index 88b8c510507f..f1c1c232af52 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -352,6 +352,9 @@ dependencies { // upon each update first test: new registration, receive push gplayImplementation "com.google.firebase:firebase-messaging:23.0.7" + + // TODO change back to tag before merging + implementation 'com.github.nextcloud.android-common:ui:feature/more-theming-files-SNAPSHOT' } configurations.all { diff --git a/app/src/main/java/com/nextcloud/client/di/ThemeModule.kt b/app/src/main/java/com/nextcloud/client/di/ThemeModule.kt index 26e9c1a07de3..52e8a6930f9f 100644 --- a/app/src/main/java/com/nextcloud/client/di/ThemeModule.kt +++ b/app/src/main/java/com/nextcloud/client/di/ThemeModule.kt @@ -21,6 +21,7 @@ package com.nextcloud.client.di import android.content.Context +import com.nextcloud.android.common.ui.theme.MaterialSchemes import com.owncloud.android.utils.theme.ThemeAvatarUtils import com.owncloud.android.utils.theme.ThemeBarUtils import com.owncloud.android.utils.theme.ThemeButtonUtils @@ -35,97 +36,112 @@ import com.owncloud.android.utils.theme.ThemeTextInputUtils import com.owncloud.android.utils.theme.ThemeTextUtils import com.owncloud.android.utils.theme.ThemeToolbarUtils import com.owncloud.android.utils.theme.ThemeUtils +import com.owncloud.android.utils.theme.newm3.MaterialSchemesProvider +import com.owncloud.android.utils.theme.newm3.MaterialSchemesProviderImpl +import dagger.Binds import dagger.Module import dagger.Provides import javax.inject.Singleton @Module -internal class ThemeModule { - @Provides - @Singleton - fun themeColorUtils(): ThemeColorUtils { - return ThemeColorUtils() - } +internal abstract class ThemeModule { - @Provides - @Singleton - fun themeFabUtils(themeColorUtils: ThemeColorUtils?, themeDrawableUtils: ThemeDrawableUtils?): ThemeFabUtils { - return ThemeFabUtils(themeColorUtils, themeDrawableUtils) - } + @Binds + abstract fun bindMaterialSchemesProvider(provider: MaterialSchemesProviderImpl): MaterialSchemesProvider - @Provides - @Singleton - fun themeLayoutUtils(themeColorUtils: ThemeColorUtils?): ThemeLayoutUtils { - return ThemeLayoutUtils(themeColorUtils) - } + companion object { - @Provides - @Singleton - fun themeToolbarUtils( - themeColorUtils: ThemeColorUtils?, - themeDrawableUtils: ThemeDrawableUtils?, - themeTextInputUtils: ThemeTextInputUtils? - ): ThemeToolbarUtils { - return ThemeToolbarUtils(themeColorUtils, themeDrawableUtils, themeTextInputUtils) - } + @Provides + @Singleton + fun themeColorUtils(): ThemeColorUtils { + return ThemeColorUtils() + } - @Provides - @Singleton - fun themeDrawableUtils(context: Context?): ThemeDrawableUtils { - return ThemeDrawableUtils(context) - } + @Provides + @Singleton + fun themeFabUtils(themeColorUtils: ThemeColorUtils?, themeDrawableUtils: ThemeDrawableUtils?): ThemeFabUtils { + return ThemeFabUtils(themeColorUtils, themeDrawableUtils) + } - @Provides - @Singleton - fun themeUtils(): ThemeUtils { - return ThemeUtils() - } + @Provides + @Singleton + fun themeLayoutUtils(themeColorUtils: ThemeColorUtils?): ThemeLayoutUtils { + return ThemeLayoutUtils(themeColorUtils) + } - @Provides - @Singleton - fun themeMenuUtils(): ThemeMenuUtils { - return ThemeMenuUtils() - } + @Provides + @Singleton + fun themeToolbarUtils( + themeColorUtils: ThemeColorUtils?, + themeDrawableUtils: ThemeDrawableUtils?, + themeTextInputUtils: ThemeTextInputUtils? + ): ThemeToolbarUtils { + return ThemeToolbarUtils(themeColorUtils, themeDrawableUtils, themeTextInputUtils) + } - @Provides - @Singleton - fun themeSnackbarUtils(): ThemeSnackbarUtils { - return ThemeSnackbarUtils() - } + @Provides + @Singleton + fun themeDrawableUtils(context: Context?): ThemeDrawableUtils { + return ThemeDrawableUtils(context) + } - @Provides - @Singleton - fun themeTextUtils(): ThemeTextUtils { - return ThemeTextUtils() - } + @Provides + @Singleton + fun themeUtils(): ThemeUtils { + return ThemeUtils() + } - @Provides - @Singleton - fun themeButtonUtils(): ThemeButtonUtils { - return ThemeButtonUtils() - } + @Provides + @Singleton + fun themeMenuUtils(): ThemeMenuUtils { + return ThemeMenuUtils() + } - @Provides - @Singleton - fun themeBarUtils(): ThemeBarUtils { - return ThemeBarUtils() - } + @Provides + @Singleton + fun themeSnackbarUtils(): ThemeSnackbarUtils { + return ThemeSnackbarUtils() + } - @Provides - @Singleton - fun themeTextInputUtils(): ThemeTextInputUtils { - return ThemeTextInputUtils() - } + @Provides + @Singleton + fun themeTextUtils(): ThemeTextUtils { + return ThemeTextUtils() + } - @Provides - @Singleton - fun themeCheckableUtils(): ThemeCheckableUtils { - return ThemeCheckableUtils() - } + @Provides + @Singleton + fun themeButtonUtils(): ThemeButtonUtils { + return ThemeButtonUtils() + } + + @Provides + @Singleton + fun themeBarUtils(): ThemeBarUtils { + return ThemeBarUtils() + } + + @Provides + @Singleton + fun themeTextInputUtils(): ThemeTextInputUtils { + return ThemeTextInputUtils() + } + + @Provides + @Singleton + fun themeCheckableUtils(): ThemeCheckableUtils { + return ThemeCheckableUtils() + } + + @Provides + @Singleton + fun themeAvatarUtils(): ThemeAvatarUtils { + return ThemeAvatarUtils() + } - @Provides - @Singleton - fun themeAvatarUtils(): ThemeAvatarUtils { - return ThemeAvatarUtils() + @Provides + fun provideMaterialSchemes(materialSchemesProvider: MaterialSchemesProvider): MaterialSchemes { + return materialSchemesProvider.getMaterialSchemesForCurrentUser() + } } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index a188cddbfd5f..250c34009e21 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -111,9 +111,9 @@ import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.theme.ThemeAvatarUtils; import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeFabUtils; import com.owncloud.android.utils.theme.ThemeToolbarUtils; import com.owncloud.android.utils.theme.ThemeUtils; +import com.owncloud.android.utils.theme.newm3.ViewThemeUtils; import org.apache.commons.httpclient.HttpStatus; import org.greenrobot.eventbus.EventBus; @@ -196,12 +196,12 @@ public class OCFileListFragment extends ExtendedListFragment implements @Inject ClientFactory clientFactory; @Inject Throttler throttler; @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeFabUtils themeFabUtils; @Inject ThemeToolbarUtils themeToolbarUtils; @Inject ThemeUtils themeUtils; @Inject ThemeAvatarUtils themeAvatarUtils; @Inject ArbitraryDataProvider arbitraryDataProvider; @Inject BackgroundJobManager backgroundJobManager; + @Inject ViewThemeUtils viewThemeUtils; protected FileFragment.ContainerActivity mContainerActivity; @@ -321,7 +321,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, mFabMain = requireActivity().findViewById(R.id.fab_main); if (mFabMain != null) { // is not available in FolderPickerActivity - themeFabUtils.colorFloatingActionButton(mFabMain, R.drawable.ic_plus, requireContext()); + viewThemeUtils.material.themeFAB(mFabMain); } Log_OC.i(TAG, "onCreateView() end"); @@ -472,7 +472,7 @@ public void registerFabListener() { FileActivity activity = (FileActivity) getActivity(); if (mFabMain != null) { // is not available in FolderPickerActivity - themeFabUtils.colorFloatingActionButton(mFabMain, R.drawable.ic_plus, requireContext()); + viewThemeUtils.material.themeFAB(mFabMain); mFabMain.setOnClickListener(v -> { final OCFileListBottomSheetDialogFragment dialog = new OCFileListBottomSheetDialogFragment(activity, @@ -1871,7 +1871,7 @@ public void setFabVisible(final boolean visible) { getActivity().runOnUiThread(() -> { if (visible) { mFabMain.show(); - themeFabUtils.colorFloatingActionButton(mFabMain, requireContext()); + viewThemeUtils.material.themeFAB(mFabMain); } else { mFabMain.hide(); } @@ -1921,10 +1921,10 @@ public void setFabEnabled(final boolean enabled) { getActivity().runOnUiThread(() -> { if (enabled) { mFabMain.setEnabled(true); - themeFabUtils.colorFloatingActionButton(mFabMain, requireContext()); + viewThemeUtils.material.themeFAB(mFabMain); } else { mFabMain.setEnabled(false); - themeFabUtils.colorFloatingActionButton(mFabMain, requireContext(), Color.GRAY); + viewThemeUtils.material.themeFAB(mFabMain); } }); } diff --git a/app/src/main/java/com/owncloud/android/utils/theme/newm3/MaterialSchemesProvider.kt b/app/src/main/java/com/owncloud/android/utils/theme/newm3/MaterialSchemesProvider.kt new file mode 100644 index 000000000000..9237407f1abd --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/newm3/MaterialSchemesProvider.kt @@ -0,0 +1,33 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.owncloud.android.utils.theme.newm3 + +import com.nextcloud.android.common.ui.theme.MaterialSchemes +import com.nextcloud.client.account.User +import com.owncloud.android.lib.resources.status.OCCapability + +interface MaterialSchemesProvider { + fun getMaterialSchemesForUser(user: User): MaterialSchemes + fun getMaterialSchemesForCapability(capability: OCCapability): MaterialSchemes + fun getMaterialSchemesForCurrentUser(): MaterialSchemes +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/newm3/MaterialSchemesProviderImpl.kt b/app/src/main/java/com/owncloud/android/utils/theme/newm3/MaterialSchemesProviderImpl.kt new file mode 100644 index 000000000000..a6365a87cd25 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/newm3/MaterialSchemesProviderImpl.kt @@ -0,0 +1,63 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.owncloud.android.utils.theme.newm3 + +import android.content.Context +import com.nextcloud.android.common.ui.theme.MaterialSchemes +import com.nextcloud.client.account.User +import com.nextcloud.client.account.UserAccountManager +import com.owncloud.android.lib.resources.status.OCCapability +import com.owncloud.android.utils.theme.CapabilityUtils +import java.util.concurrent.ConcurrentHashMap +import javax.inject.Inject + +// TODO think about assisted inject to pass user instead of fetching it from userAccountManager, thus making it more efficient +// or cache the user, IDK +internal class MaterialSchemesProviderImpl @Inject constructor( + private val context: Context, + private val userAccountManager: UserAccountManager, + private val themeFactory: ServerThemeImpl.Factory +) : MaterialSchemesProvider { + + private val themeCache: MutableMap = ConcurrentHashMap() + + override fun getMaterialSchemesForUser(user: User): MaterialSchemes { + val url: String = user.server.uri.toString() + + if (!themeCache.containsKey(url)) { + val capability = CapabilityUtils.getCapability(user, context) + themeCache[url] = getMaterialSchemesForCapability(capability) + } + + return themeCache[url]!! + } + + override fun getMaterialSchemesForCapability(capability: OCCapability): MaterialSchemes { + val serverTheme = themeFactory.create(capability) + return MaterialSchemes.fromServerTheme(serverTheme) + } + + override fun getMaterialSchemesForCurrentUser(): MaterialSchemes { + return getMaterialSchemesForUser(userAccountManager.user) + } +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/newm3/ServerThemeImpl.kt b/app/src/main/java/com/owncloud/android/utils/theme/newm3/ServerThemeImpl.kt new file mode 100644 index 000000000000..d87e07c57450 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/newm3/ServerThemeImpl.kt @@ -0,0 +1,55 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.owncloud.android.utils.theme.newm3 + +import com.nextcloud.android.common.ui.color.ColorUtil +import com.nextcloud.android.common.ui.theme.ServerTheme +import com.owncloud.android.R +import com.owncloud.android.lib.resources.status.OCCapability +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +class ServerThemeImpl @AssistedInject constructor(colorUtil: ColorUtil, @Assisted capability: OCCapability) : + ServerTheme { + override val colorElement: Int + override val colorElementBright: Int + override val colorElementDark: Int + override val colorText: Int + override val primaryColor: Int + + init { + primaryColor = + colorUtil.getNullSafeColorWithFallbackRes(capability.serverColor, R.color.colorPrimary) + colorElement = colorUtil.getNullSafeColor(capability.serverElementColor, primaryColor) + colorElementBright = + colorUtil.getNullSafeColor(capability.serverElementColorBright, primaryColor) + colorElementDark = colorUtil.getNullSafeColor(capability.serverElementColorDark, primaryColor) + colorText = colorUtil.getTextColor(capability.serverTextColor, primaryColor) + } + + @AssistedFactory + interface Factory { + fun create(capability: OCCapability): ServerThemeImpl + } +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/newm3/ViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/newm3/ViewThemeUtils.kt new file mode 100644 index 000000000000..2b29b108d770 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/newm3/ViewThemeUtils.kt @@ -0,0 +1,43 @@ +/* + * Nextcloud Talk application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 . + */ + +package com.owncloud.android.utils.theme.newm3 + +import com.nextcloud.android.common.ui.theme.MaterialSchemes +import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase +import com.nextcloud.android.common.ui.theme.utils.AndroidViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.AndroidXViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.DialogViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.MaterialViewThemeUtils +import javax.inject.Inject + +@Suppress("TooManyFunctions") +class ViewThemeUtils @Inject constructor( + schemes: MaterialSchemes, + @JvmField + val platform: AndroidViewThemeUtils, + @JvmField + val material: MaterialViewThemeUtils, + @JvmField + val androidx: AndroidXViewThemeUtils, + @JvmField + val dialog: DialogViewThemeUtils +) : ViewThemeUtilsBase(schemes) diff --git a/app/src/main/res/layout/files.xml b/app/src/main/res/layout/files.xml index 2e58f45e3ede..2dff26476047 100644 --- a/app/src/main/res/layout/files.xml +++ b/app/src/main/res/layout/files.xml @@ -18,6 +18,8 @@ --> + app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior" + app:srcCompat="@drawable/ic_plus" + tools:visibility="visible"/> diff --git a/settings.gradle b/settings.gradle index 40b70bd250d3..bb095760ccf5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,9 @@ rootProject.name = 'Nextcloud' include ':app' + +//includeBuild('../android-common') { +// dependencySubstitution { +// substitute module('com.github.nextcloud.android-common:ui') using project(':ui') +// } +//}