Base framework for server theming

Includes PoC with ConversationListController's FAB

Signed-off-by: Álvaro Brey <alvaro.brey@nextcloud.com>
This commit is contained in:
Álvaro Brey 2022-07-14 17:46:11 +02:00 committed by Andy Scherzinger
parent 768cb06999
commit 9bbeb9b420
No known key found for this signature in database
GPG Key ID: 6CADC7E3523C308B
10 changed files with 286 additions and 4 deletions

View File

@ -61,6 +61,7 @@ import com.nextcloud.talk.dagger.modules.ViewModelModule
import com.nextcloud.talk.jobs.AccountRemovalWorker import com.nextcloud.talk.jobs.AccountRemovalWorker
import com.nextcloud.talk.jobs.CapabilitiesWorker import com.nextcloud.talk.jobs.CapabilitiesWorker
import com.nextcloud.talk.jobs.SignalingSettingsWorker import com.nextcloud.talk.jobs.SignalingSettingsWorker
import com.nextcloud.talk.ui.theme.ThemeModule
import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.DeviceUtils import com.nextcloud.talk.utils.DeviceUtils
import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils
@ -96,7 +97,8 @@ import javax.inject.Singleton
ArbitraryStorageModule::class, ArbitraryStorageModule::class,
ViewModelModule::class, ViewModelModule::class,
RepositoryModule::class, RepositoryModule::class,
UtilsModule::class UtilsModule::class,
ThemeModule::class
] ]
) )
@Singleton @Singleton
@ -120,6 +122,7 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
override fun preKey(database: SQLiteDatabase) { override fun preKey(database: SQLiteDatabase) {
// unused atm // unused atm
} }
override fun postKey(database: SQLiteDatabase) { override fun postKey(database: SQLiteDatabase) {
Log.i("TalkApplication", "DB cipher_migrate START") Log.i("TalkApplication", "DB cipher_migrate START")
database.rawExecSQL("PRAGMA cipher_migrate;") database.rawExecSQL("PRAGMA cipher_migrate;")

View File

@ -92,6 +92,8 @@ import com.nextcloud.talk.models.json.statuses.StatusesOverall;
import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository; import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository;
import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment; import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment;
import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog; import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog;
import com.nextcloud.talk.ui.theme.ServerTheme;
import com.nextcloud.talk.ui.theme.ViewThemeUtils;
import com.nextcloud.talk.users.UserManager; import com.nextcloud.talk.users.UserManager;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.AttendeePermissionsUtil; import com.nextcloud.talk.utils.AttendeePermissionsUtil;
@ -181,6 +183,9 @@ public class ConversationsListController extends BaseController implements Flexi
@Inject @Inject
UnifiedSearchRepository unifiedSearchRepository; UnifiedSearchRepository unifiedSearchRepository;
@Inject
ServerTheme serverTheme;
@BindView(R.id.recycler_view) @BindView(R.id.recycler_view)
RecyclerView recyclerView; RecyclerView recyclerView;
@ -784,6 +789,7 @@ public class ConversationsListController extends BaseController implements Flexi
ContactAddressBookWorker.Companion.run(context); ContactAddressBookWorker.Companion.run(context);
showNewConversationsScreen(); showNewConversationsScreen();
}); });
new ViewThemeUtils(serverTheme).themeFAB(floatingActionButton);
if (getActivity() != null && getActivity() instanceof MainActivity) { if (getActivity() != null && getActivity() instanceof MainActivity) {
MainActivity activity = (MainActivity) getActivity(); MainActivity activity = (MainActivity) getActivity();

View File

@ -43,6 +43,11 @@ data class ThemingCapability(
var colorText: String?, var colorText: String?,
@JsonField(name = ["color-element"]) @JsonField(name = ["color-element"])
var colorElement: String?, var colorElement: String?,
// TODO check what happens with users with already fetched capabilities
@JsonField(name = ["color-element-bright"])
var colorElementBright: String?,
@JsonField(name = ["color-element-dark"])
var colorElementDark: String?,
@JsonField(name = ["logo"]) @JsonField(name = ["logo"])
var logo: String?, var logo: String?,
@JsonField(name = ["background"]) @JsonField(name = ["background"])
@ -53,5 +58,5 @@ data class ThemingCapability(
var backgroundDefault: Boolean? var backgroundDefault: Boolean?
) : Parcelable { ) : Parcelable {
// This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject'
constructor() : this(null, null, null, null, null, null, null, null, null, null) constructor() : this(null, null, null, null, null, null, null, null, null, null, null, null)
} }

View File

@ -0,0 +1,53 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.ui.theme
import androidx.annotation.ColorInt
interface ServerTheme {
@get:ColorInt
val primaryColor: Int
/**
* Default element color
*/
@get:ColorInt
val colorElement: Int
/**
* Element color for bright backgrounds
*/
@get:ColorInt
val colorElementBright: Int
/**
* Element color for dark backgrounds
*/
@get:ColorInt
val colorElementDark: Int
/**
* Text color for elements
*/
@get:ColorInt
val colorText: Int
}

View File

@ -0,0 +1,45 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.ui.theme
import android.content.Context
import android.graphics.Color
import com.nextcloud.talk.models.json.capabilities.ThemingCapability
internal class ServerThemeImpl(context: Context, themingCapability: ThemingCapability) :
ServerTheme {
override val primaryColor: Int
override val colorElement: Int
override val colorElementBright: Int
override val colorElementDark: Int
override val colorText: Int
// TODO fallback when some of these are null
init {
primaryColor = Color.parseColor(themingCapability.color!!)
colorElement = Color.parseColor(themingCapability.colorElement!!)
colorElementBright = Color.parseColor(themingCapability.colorElementBright!!)
colorElementDark = Color.parseColor(themingCapability.colorElementDark!!)
colorText = Color.parseColor(themingCapability.colorText!!)
}
}

View File

@ -0,0 +1,31 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.ui.theme
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.models.json.capabilities.Capabilities
interface ServerThemeProvider {
fun getServerThemeForUser(user: User): ServerTheme
fun getServerThemeForCurrentUser(): ServerTheme
fun getServerThemeForCapabilities(capabilities: Capabilities): ServerTheme
}

View File

@ -0,0 +1,46 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.ui.theme
import android.content.Context
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.models.json.capabilities.Capabilities
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
// TODO cache theme, keyed by server url
internal class ServerThemeProviderImpl(
private val context: Context,
private val userProvider: CurrentUserProviderNew
) :
ServerThemeProvider {
override fun getServerThemeForUser(user: User): ServerTheme {
return getServerThemeForCapabilities(user.capabilities!!)
}
override fun getServerThemeForCurrentUser(): ServerTheme {
return getServerThemeForUser(userProvider.currentUser.blockingGet())
}
override fun getServerThemeForCapabilities(capabilities: Capabilities): ServerTheme {
return ServerThemeImpl(context, capabilities.themingCapability!!)
}
}

View File

@ -0,0 +1,45 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.ui.theme
import android.content.Context
import com.nextcloud.talk.dagger.modules.ContextModule
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
import com.nextcloud.talk.utils.database.user.UserModule
import dagger.Module
import dagger.Provides
import dagger.Reusable
@Module(includes = [ContextModule::class, UserModule::class])
class ThemeModule {
@Provides
@Reusable
fun provideServerThemeProvider(context: Context, userProvider: CurrentUserProviderNew): ServerThemeProvider {
return ServerThemeProviderImpl(context, userProvider)
}
@Provides
fun provideCurrentServerTheme(themeProvider: ServerThemeProvider): ServerTheme {
return themeProvider.getServerThemeForCurrentUser()
}
}

View File

@ -0,0 +1,48 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.ui.theme
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Configuration
import com.google.android.material.floatingactionbutton.FloatingActionButton
class ViewThemeUtils(val theme: ServerTheme) {
private fun isDarkMode(context: Context): Boolean = when (
context.resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK
) {
Configuration.UI_MODE_NIGHT_YES -> true
else -> false
}
private fun getElementColor(context: Context): Int = when {
isDarkMode(context) -> theme.colorElementDark
else -> theme.colorElementBright
}
fun themeFAB(fab: FloatingActionButton) {
fab.backgroundTintList = ColorStateList.valueOf(getElementColor(fab.context))
fab.imageTintList = ColorStateList.valueOf(theme.colorText)
}
}

View File

@ -115,11 +115,11 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_margin="16dp" android:layout_margin="16dp"
android:backgroundTint="@color/colorPrimary"
android:contentDescription="@string/nc_new_conversation" android:contentDescription="@string/nc_new_conversation"
app:borderWidth="0dp" app:borderWidth="0dp"
app:srcCompat="@drawable/ic_add_white_24px" app:srcCompat="@drawable/ic_add_white_24px"
app:tint="@color/white" /> app:tint="@color/white"
app:backgroundTint="@color/colorPrimary"/>
<com.nextcloud.ui.popupbubble.PopupBubble <com.nextcloud.ui.popupbubble.PopupBubble
android:id="@+id/newMentionPopupBubble" android:id="@+id/newMentionPopupBubble"