feat(darklogo): port customDarkLogo (#20922)

This commit is contained in:
Átila 2024-08-21 14:58:32 -03:00 committed by GitHub
parent 4ca3084db5
commit c48e93e00c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 140 additions and 5 deletions

View File

@ -8,6 +8,7 @@ case class MeetingSystemColumnsDbModel(
loginUrl: Option[String],
logoutUrl: Option[String],
customLogoUrl: Option[String],
customDarkLogoUrl: Option[String],
bannerText: Option[String],
bannerColor: Option[String],
)
@ -70,9 +71,10 @@ class MeetingDbTableDef(tag: Tag) extends Table[MeetingDbModel](tag, None, "meet
val loginUrl = column[Option[String]]("loginUrl")
val logoutUrl = column[Option[String]]("logoutUrl")
val customLogoUrl = column[Option[String]]("customLogoUrl")
val customDarkLogoUrl = column[Option[String]]("customDarkLogoUrl")
val bannerText = column[Option[String]]("bannerText")
val bannerColor = column[Option[String]]("bannerColor")
val systemColumns = (loginUrl, logoutUrl, customLogoUrl, bannerText, bannerColor) <> (MeetingSystemColumnsDbModel.tupled, MeetingSystemColumnsDbModel.unapply)
val systemColumns = (loginUrl, logoutUrl, customLogoUrl, customDarkLogoUrl, bannerText, bannerColor) <> (MeetingSystemColumnsDbModel.tupled, MeetingSystemColumnsDbModel.unapply)
val createdTime = column[Long]("createdTime")
val durationInSeconds = column[Int]("durationInSeconds")
val endWhenNoModerator = column[Boolean]("endWhenNoModerator")
@ -111,6 +113,10 @@ object MeetingDAO {
case "" => None
case logoUrl => Some(logoUrl)
},
customDarkLogoUrl = meetingProps.systemProps.customDarkLogoURL match {
case "" => None
case darkLogoUrl => Some(darkLogoUrl)
},
bannerText = meetingProps.systemProps.bannerText match {
case "" => None
case bannerText => Some(bannerText)

View File

@ -73,6 +73,7 @@ case class SystemProps(
loginUrl: String,
logoutUrl: String,
customLogoURL: String,
customDarkLogoURL: String,
bannerText: String,
bannerColor: String,
)

View File

@ -37,6 +37,7 @@ public class ApiParams {
public static final String MEETING_LAYOUT = "meetingLayout";
public static final String IS_BREAKOUT = "isBreakout";
public static final String LOGO = "logo";
public static final String DARK_LOGO = "darklogo";
public static final String LOGOUT_TIMER = "logoutTimer";
public static final String LOGIN_URL = "loginURL";
public static final String LOGOUT_URL = "logoutURL";

View File

@ -429,7 +429,7 @@ public class MeetingService implements MessageListener {
m.getUserInactivityInspectTimerInMinutes(), m.getUserInactivityThresholdInMinutes(),
m.getUserActivitySignResponseDelayInMinutes(), m.getEndWhenNoModerator(), m.getEndWhenNoModeratorDelayInMinutes(),
m.getMuteOnStart(), m.getAllowModsToUnmuteUsers(), m.getAllowModsToEjectCameras(), m.getMeetingKeepEvents(),
m.breakoutRoomsParams, m.lockSettingsParams, m.getLoginUrl(), m.getLogoutUrl(), m.getCustomLogoURL(),
m.breakoutRoomsParams, m.lockSettingsParams, m.getLoginUrl(), m.getLogoutUrl(), m.getCustomLogoURL(), m.getCustomDarkLogoURL(),
m.getBannerText(), m.getBannerColor(), m.getGroups(), m.getDisabledFeatures(), m.getNotifyRecordingIsOn(),
m.getPresentationUploadExternalDescription(), m.getPresentationUploadExternalUrl(),
m.getOverrideClientSettings());

View File

@ -105,7 +105,9 @@ public class ParamsProcessorUtil {
private boolean defaultNotifyRecordingIsOn = false;
private boolean defaultKeepEvents = false;
private Boolean useDefaultLogo;
private Boolean useDefaultDarkLogo;
private String defaultLogoURL;
private String defaultDarkLogoURL;
private String defaultPresentationUploadExternalDescription = "";
private String defaultPresentationUploadExternalUrl = "";
@ -830,6 +832,16 @@ public class ParamsProcessorUtil {
meeting.setCustomLogoURL(this.getDefaultLogoURL());
}
if (!StringUtils.isEmpty(params.get(ApiParams.DARK_LOGO))) {
meeting.setCustomDarkLogoURL(params.get(ApiParams.DARK_LOGO));
} else if (!StringUtils.isEmpty(params.get(ApiParams.LOGO))) {
meeting.setCustomDarkLogoURL(params.get(ApiParams.LOGO));
} else if (this.getUseDefaultDarkLogo()) {
meeting.setCustomDarkLogoURL(this.getDefaultDarkLogoURL());
} else if (!this.getUseDefaultDarkLogo() && this.getUseDefaultLogo()) {
meeting.setCustomDarkLogoURL(this.getDefaultLogoURL());
}
if (!StringUtils.isEmpty(params.get(ApiParams.COPYRIGHT))) {
meeting.setCustomCopyright(params.get(ApiParams.COPYRIGHT));
}
@ -895,10 +907,18 @@ public class ParamsProcessorUtil {
return useDefaultLogo;
}
public Boolean getUseDefaultDarkLogo() {
return useDefaultDarkLogo;
}
public String getDefaultLogoURL() {
return defaultLogoURL;
}
public String getDefaultDarkLogoURL() {
return defaultDarkLogoURL;
}
public Boolean getAllowRequestsWithoutSession() {
return allowRequestsWithoutSession;
}
@ -1262,10 +1282,19 @@ public class ParamsProcessorUtil {
this.useDefaultLogo = value;
}
public void setUseDefaultDarkLogo(Boolean value) {
this.useDefaultDarkLogo = value;
}
public void setDefaultLogoURL(String url) {
this.defaultLogoURL = url;
}
public void setDefaultDarkLogoURL(String url) {
this.defaultDarkLogoURL = url;
}
public void setAllowRequestsWithoutSession(Boolean allowRequestsWithoutSession) {
this.allowRequestsWithoutSession = allowRequestsWithoutSession;
}

View File

@ -95,6 +95,7 @@ public class Meeting {
private final List<String> breakoutRooms = new ArrayList<>();
private ArrayList<Group> groups = new ArrayList<Group>();
private String customLogoURL = "";
private String customDarkLogoURL = "";
private String customCopyright = "";
private Boolean muteOnStart = false;
private Boolean allowModsToUnmuteUsers = false;
@ -643,10 +644,18 @@ public class Meeting {
return customLogoURL;
}
public String getCustomDarkLogoURL() {
return customDarkLogoURL;
}
public void setCustomLogoURL(String url) {
customLogoURL = url;
}
public void setCustomDarkLogoURL(String url) {
customDarkLogoURL = url;
}
public void setCustomCopyright(String copyright) {
customCopyright = copyright;
}

View File

@ -61,6 +61,7 @@ public interface IBbbWebApiGWApp {
String loginUrl,
String logoutUrl,
String customLogoURL,
String customDarkLogoURL,
String bannerText,
String bannerColor,
ArrayList<Group> groups,

View File

@ -157,6 +157,7 @@ class BbbWebApiGWApp(
loginUrl: String,
logoutUrl: String,
customLogoURL: String,
customDarkLogoURL: String,
bannerText: String,
bannerColor: String,
groups: java.util.ArrayList[Group],
@ -247,6 +248,7 @@ class BbbWebApiGWApp(
},
logoutUrl,
customLogoURL,
customDarkLogoURL,
bannerText match {
case t: String => t
case _ => ""

View File

@ -33,6 +33,7 @@ create table "meeting" (
"loginUrl" varchar(500),
"logoutUrl" varchar(500),
"customLogoUrl" varchar(500),
"customDarkLogoUrl" varchar(500),
"bannerText" text,
"bannerColor" varchar(50),
"createdTime" bigint,

View File

@ -161,6 +161,7 @@ select_permissions:
- createdAt
- createdTime
- customLogoUrl
- customDarkLogoUrl
- disabledFeatures
- durationInSeconds
- endWhenNoModerator
@ -190,6 +191,7 @@ select_permissions:
- bannerColor
- bannerText
- customLogoUrl
- customDarkLogoUrl
- ended
- endedAt
- endedBy

View File

@ -2,6 +2,15 @@ import * as DarkReader from 'darkreader';
import Styled from './styles';
import logger from '/imports/startup/client/logger';
import useMeeting from '../../core/hooks/useMeeting';
import Storage from '/imports/ui/services/storage/session';
const CUSTOM_LOGO_URL_KEY = 'CustomLogoUrl';
const CUSTOM_DARK_LOGO_URL_KEY = 'CustomDarkLogoUrl';
const equalURLs = () => (
Storage.getItem(CUSTOM_LOGO_URL_KEY) === Storage.getItem(CUSTOM_DARK_LOGO_URL_KEY)
);
export function useMeetingIsBreakout() {
const { data: meeting } = useMeeting((m) => ({
@ -12,11 +21,17 @@ export function useMeetingIsBreakout() {
}
export const setDarkTheme = (value) => {
let invert = [Styled.DtfInvert];
if(equalURLs()) {
invert = [Styled.DtfBrandingInvert];
}
if (value && !DarkReader.isEnabled()) {
DarkReader.enable(
{ brightness: 100, contrast: 90 },
{
invert: [Styled.DtfInvert],
invert,
ignoreInlineStyle: [Styled.DtfCss],
ignoreImageAnalysis: [Styled.DtfImages],
},

View File

@ -23,6 +23,41 @@ const ActionsBar = styled.section`
const Layout = styled(FlexColumn)``;
const DtfInvert = `
body {
background-color: var(--darkreader-neutral-background) !important;
}
header[id="Navbar"] {
background-color: var(--darkreader-neutral-background) !important;
}
section[id="ActionsBar"] {
background-color: var(--darkreader-neutral-background) !important;
}
select {
border: 0.1rem solid #FFFFFF !important;
}
select[data-test="skipSlide"] {
border: unset !important;
}
div[data-test="presentationContainer"] {
background-color: var(--darkreader-neutral-background) !important;
}
select {
border-top: unset !important;
border-right: unset !important;
border-left: unset !important;
}
.tl-container {
background-color: var(--tl-background) !important;
}
#TD-Tools button, #TD-TopPanel-Undo, #TD-TopPanel-Redo, #TD-Styles {
border-color: transparent !important;
}
[id="TD-StylesMenu"],
[id="TD-Styles-Color-Container"],
#connectionBars > div
`;
const DtfBrandingInvert = `
body {
background-color: var(--darkreader-neutral-background) !important;
}
@ -73,6 +108,7 @@ export default {
ActionsBar,
Layout,
DtfInvert,
DtfBrandingInvert,
DtfCss,
DtfImages,
};

View File

@ -42,6 +42,7 @@ interface PresenceManagerProps extends PresenceManagerContainerProps {
bannerColor: string;
bannerText: string;
customLogoUrl: string;
customDarkLogoUrl: string;
loggedOut: boolean;
guestStatus: string;
guestLobbyMessage: string | null;
@ -67,6 +68,7 @@ const PresenceManager: React.FC<PresenceManagerProps> = ({
bannerColor,
bannerText,
customLogoUrl,
customDarkLogoUrl,
loggedOut,
guestLobbyMessage,
guestStatus,
@ -112,6 +114,7 @@ const PresenceManager: React.FC<PresenceManagerProps> = ({
extId,
meetingName,
customLogoUrl,
customDarkLogoUrl,
});
}, []);
@ -227,6 +230,7 @@ const PresenceManagerContainer: React.FC<PresenceManagerContainerProps> = ({ chi
bannerColor,
bannerText,
customLogoUrl,
customDarkLogoUrl,
} = userInfoData.meeting[0];
const { extId, name: userName, userId } = userInfoData.user_current[0];
@ -250,6 +254,7 @@ const PresenceManagerContainer: React.FC<PresenceManagerContainerProps> = ({ chi
bannerText={bannerText}
loggedOut={loggedOut}
customLogoUrl={customLogoUrl}
customDarkLogoUrl={customDarkLogoUrl}
guestLobbyMessage={guestStatusDetails?.guestLobbyMessage ?? null}
positionInWaitingQueue={guestStatusDetails?.positionInWaitingQueue ?? null}
guestStatus={guestStatus}

View File

@ -32,6 +32,7 @@ export interface GetUserInfoResponse {
bannerColor: string;
bannerText: string;
customLogoUrl: string;
customDarkLogoUrl: string;
}>;
user_current: Array<{
extId: string;
@ -49,6 +50,7 @@ query getUserInfo {
bannerColor
bannerText
customLogoUrl
customDarkLogoUrl
}
user_current {
extId

View File

@ -23,6 +23,7 @@ export const setUserDataToSessionStorage = (userData: {
extId: string,
meetingName: string,
customLogoUrl: string,
customDarkLogoUrl: string,
}) => {
sessionStorage.setItem('meetingId', userData.meetingId);
sessionStorage.setItem('userId', userData.userId);
@ -32,6 +33,7 @@ export const setUserDataToSessionStorage = (userData: {
sessionStorage.setItem('extId', userData.extId);
sessionStorage.setItem('meetingName', userData.meetingName);
Storage.setItem('CustomLogoUrl', userData.customLogoUrl);
Storage.setItem('CustomDarkLogoUrl', userData.customDarkLogoUrl);
};
export default {

View File

@ -8,12 +8,15 @@ import UserContentContainer from './user-list-content/container';
const propTypes = {
compact: PropTypes.bool,
CustomLogoUrl: PropTypes.string,
CustomDarkLogoUrl: PropTypes.string,
DarkModeIsEnabled: PropTypes.bool,
showBranding: PropTypes.bool.isRequired,
};
const defaultProps = {
compact: false,
CustomLogoUrl: null,
CustomDarkLogoUrl: null,
};
class UserList extends PureComponent {
@ -21,16 +24,19 @@ class UserList extends PureComponent {
const {
compact,
CustomLogoUrl,
CustomDarkLogoUrl,
DarkModeIsEnabled,
showBranding,
} = this.props;
const logoUrl = DarkModeIsEnabled ? CustomDarkLogoUrl : CustomLogoUrl;
return (
<Styled.UserList>
{
showBranding
&& !compact
&& CustomLogoUrl
? <CustomLogo CustomLogoUrl={CustomLogoUrl} /> : null
&& logoUrl
? <CustomLogo CustomLogoUrl={logoUrl} /> : null
}
<UserContentContainer compact={compact} />
</Styled.UserList>

View File

@ -1,13 +1,19 @@
import React from 'react';
import getFromUserSettings from '/imports/ui/services/users-settings';
import { isDarkThemeEnabled } from '/imports/ui/components/app/service';
import UserList from './component';
import { useStorageKey } from '../../services/storage/hooks';
const UserListContainer = (props) => {
const CustomLogoUrl = useStorageKey('CustomLogoUrl', 'session');
const CustomDarkLogoUrl = useStorageKey('CustomDarkLogoUrl', 'session');
const DarkModeIsEnabled = isDarkThemeEnabled();
return (
<UserList
CustomLogoUrl={CustomLogoUrl}
CustomDarkLogoUrl={CustomDarkLogoUrl}
DarkModeIsEnabled={DarkModeIsEnabled}
{...props}
showBranding={getFromUserSettings('bbb_display_branding_area', window.meetingClientSettings.public.app.branding.displayBrandingArea)}
/>

View File

@ -20,12 +20,18 @@ const STARTED_CHAT_LIST_KEY = 'startedChatList';
const CUSTOM_LOGO_URL_KEY = 'CustomLogoUrl';
const CUSTOM_DARK_LOGO_URL_KEY = 'CustomDarkLogoUrl';
export const setCustomLogoUrl = (path) => Storage.setItem(CUSTOM_LOGO_URL_KEY, path);
export const setCustomDarkLogoUrl = (path) => Storage.setItem(CUSTOM_DARK_LOGO_URL_KEY, path);
export const setModeratorOnlyMessage = (msg) => Storage.setItem('ModeratorOnlyMessage', msg);
const getCustomLogoUrl = () => Storage.getItem(CUSTOM_LOGO_URL_KEY);
const getCustomDarkLogoUrl = () => Storage.getItem(CUSTOM_DARK_LOGO_URL_KEY);
const sortByWhiteboardAccess = (a, b) => {
const _a = a.whiteboardAccess;
const _b = b.whiteboardAccess;
@ -453,6 +459,7 @@ export default {
isPublicChat,
roving,
getCustomLogoUrl,
getCustomDarkLogoUrl,
focusFirstDropDownItem,
sortUsersByCurrent,
UserJoinedMeetingAlert,

View File

@ -317,7 +317,9 @@ graphqlApiUrl=${bigbluebutton.web.serverURL}/api/rest
sessionsCleanupDelayInMinutes=60
useDefaultLogo=false
useDefaultDarkLogo=false
defaultLogoURL=${bigbluebutton.web.serverURL}/images/logo.png
defaultDarkLogoURL=${bigbluebutton.web.serverURL}/images/darklogo.png
# Allow requests without JSESSIONID to be handled (default = false)
allowRequestsWithoutSession=false

View File

@ -144,7 +144,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<property name="graphqlWebsocketUrl" value="${graphqlWebsocketUrl}"/>
<property name="graphqlApiUrl" value="${graphqlApiUrl}"/>
<property name="useDefaultLogo" value="${useDefaultLogo}"/>
<property name="useDefaultDarkLogo" value="${useDefaultDarkLogo}"/>
<property name="defaultLogoURL" value="${defaultLogoURL}"/>
<property name="defaultDarkLogoURL" value="${defaultDarkLogoURL}"/>
<property name="allowRequestsWithoutSession" value="${allowRequestsWithoutSession}"/>
<property name="defaultHttpSessionTimeout" value="${defaultHttpSessionTimeout}"/>
<property name="defaultMeetingDuration" value="${defaultMeetingDuration}"/>