SEBSERV-148 GUI implementation with expandable accordion

This commit is contained in:
anhefti 2021-04-08 08:28:18 +02:00
parent 70da5c9d66
commit d014dfe45a
10 changed files with 273 additions and 37 deletions

View file

@ -171,15 +171,16 @@ interface CellFieldBuilderAdapter {
public void createCell(final ViewGridBuilder builder) {
final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory();
final Orientation o = this.orientationsOfGroup.stream().findFirst().orElse(null);
final String groupKey = ViewGridBuilder.getGroupKey(o.groupId);
final LocTextKey groupLabelKey = new LocTextKey(
ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX +
o.groupId,
o.groupId);
groupKey,
groupKey);
final LocTextKey groupTooltipKey = new LocTextKey(
ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX +
o.groupId +
groupKey +
ExamConfigurationService.TOOL_TIP_SUFFIX,
o.groupId);
groupKey);
final Group group = widgetFactory.groupLocalized(
builder.parent,
@ -233,7 +234,7 @@ interface CellFieldBuilderAdapter {
}
this.width = this.width - this.x;
this.height = this.height - this.y + 1;
this.height = this.height - this.y + 2;
}
@Override
@ -252,7 +253,8 @@ interface CellFieldBuilderAdapter {
final ExpandBar expandBar = widgetFactory.expandBarLocalized(
builder.parent,
expandTooltipText);
expandTooltipText,
true);
expandBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, this.width, this.height + 2));
for (final Map.Entry<String, Collection<Orientation>> entry : this.orientationsOfExpandBar.entrySet()) {
@ -268,7 +270,7 @@ interface CellFieldBuilderAdapter {
this.width,
labelKey);
expandItem.setHeight(this.height * 25);
expandItem.setHeight(this.height * 23);
final Composite body = (Composite) expandItem.getControl();
final ViewGridBuilder expandBuilder = new ViewGridBuilder(
body,

View file

@ -24,18 +24,24 @@ import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
public class ProctoringViewRules implements ValueChangeRule {
public static final String KEY_ENABLE_AI = "proctoringAIEnable";
public static final String KEY_ENABLE_JITSI = "jitsiMeetEnable";
public static final String AI_GROUP_FACE_NUMBER = "proctoringDetectFaceCount";
public static final String AI_GROUP_FACE_ANGLE = "proctoringDetectFaceYaw";
public static final String KEY_ENABLE_JITSI = "jitsiMeetEnable";
public static final String JITSI_GROUP_AUDIO_VIDEO = "jitsiMeetReceiveAudio";
public static final String JITSI_GROUP_FEATURES = "jitsiMeetFeatureFlagChat";
public static final String JITSI_GROUP_CONTROLS = "jitsiMeetAudioMuted";
public static final String AI_GROUP_FACE_NUMBER = "proctoringDetectFaceCount";
public static final String AI_GROUP_FACE_ANGLE = "proctoringDetectFaceYaw";
public static final String KEY_ENABLE_ZOOM = "zoomEnable";
public static final String ZOOM_GROUP_AUDIO_VIDEO = "zoomReceiveAudio";
public static final String ZOOM_GROUP_FEATURES = "zoomFeatureFlagChat";
public static final String ZOOM_GROUP_CONTROLS = "zoomAudioMuted";
@Override
public boolean observesAttribute(final ConfigurationAttribute attribute) {
return KEY_ENABLE_AI.equals(attribute.name) || KEY_ENABLE_JITSI.equals(attribute.name);
return KEY_ENABLE_AI.equals(attribute.name) ||
KEY_ENABLE_JITSI.equals(attribute.name) ||
KEY_ENABLE_ZOOM.equals(attribute.name);
}
@Override
@ -54,6 +60,16 @@ public class ProctoringViewRules implements ValueChangeRule {
context.disableGroup(JITSI_GROUP_FEATURES);
context.disableGroup(JITSI_GROUP_CONTROLS);
}
} else if (KEY_ENABLE_ZOOM.equals(attribute.name)) {
if (BooleanUtils.toBoolean(value.value)) {
context.enableGroup(ZOOM_GROUP_AUDIO_VIDEO);
context.enableGroup(ZOOM_GROUP_FEATURES);
context.enableGroup(ZOOM_GROUP_CONTROLS);
} else {
context.disableGroup(ZOOM_GROUP_AUDIO_VIDEO);
context.disableGroup(ZOOM_GROUP_FEATURES);
context.disableGroup(ZOOM_GROUP_CONTROLS);
}
} else if (KEY_ENABLE_AI.equals(attribute.name)) {
if (BooleanUtils.toBoolean(value.value)) {
context.enableGroup(AI_GROUP_FACE_NUMBER);

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.widget;
import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_WIDGET_FUNCTION_KEY;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
@ -526,10 +527,42 @@ public class WidgetFactory {
public ExpandBar expandBarLocalized(
final Composite parent,
final LocTextKey locTooltipKey) {
final LocTextKey locTooltipKey,
final boolean exclusive) {
final ExpandBar expandBar = new ExpandBar(parent, SWT.NONE);
this.polyglotPageService.injectI18n(expandBar, locTooltipKey);
if (exclusive) {
expandBar.addListener(SWT.Expand, event -> {
try {
final Widget expandItem = event.item;
Arrays.asList(expandBar.getItems())
.stream()
.filter(item -> !item.equals(expandItem))
.forEach(item -> item.setExpanded(false));
} catch (final Exception e) {
if (log.isDebugEnabled()) {
log.warn("Failed to automate ExpandBar", e);
}
}
});
expandBar.addListener(SWT.Collapse, event -> {
try {
final Widget expandItem = event.item;
int itemIndex = Arrays.asList(expandBar.getItems()).indexOf(expandItem) + 1;
if (itemIndex >= expandBar.getItemCount()) {
itemIndex = 0;
}
expandBar.getItem(itemIndex).setExpanded(true);
} catch (final Exception e) {
if (log.isDebugEnabled()) {
log.warn("Failed to automate ExpandBar", e);
}
}
});
}
return expandBar;
}
@ -538,6 +571,7 @@ public class WidgetFactory {
final int columns,
final LocTextKey locTextKey) {
final int itemCount = parent.getItemCount();
final ExpandItem expandItem = new ExpandItem(parent, SWT.NONE);
final Composite body = new Composite(expandItem.getParent(), SWT.NONE);
final GridLayout gridLayout = new GridLayout(columns, true);
@ -546,8 +580,9 @@ public class WidgetFactory {
gridLayout.marginHeight = 0;
body.setLayout(gridLayout);
expandItem.setControl(body);
expandItem.setExpanded(itemCount == 0);
this.polyglotPageService.injectI18n(expandItem, locTextKey);
return expandItem;
}

View file

@ -1,24 +0,0 @@
INSERT IGNORE INTO configuration_attribute VALUES
(1500, 'zoomEnable', 'CHECKBOX', null, null, null, null, 'false'),
(1501, 'zoomAudioOnly', 'CHECKBOX', null, null, null, null, 'false'),
(1502, 'zoomAudioMuted', 'CHECKBOX', null, null, null, null, 'true'),
(1503, 'zoomFeatureFlagChat', 'CHECKBOX', null, null, null, null, 'false'),
(1504, 'zoomFeatureFlagCloseCaptions', 'CHECKBOX', null, null, null, null, 'false'),
(1505, 'zoomFeatureFlagDisplayMeetingName', 'CHECKBOX', null, null, null, null, 'false'),
(1506, 'zoomFeatureFlagRaiseHand', 'CHECKBOX', null, null, null, null, 'false'),
(1507, 'zoomFeatureFlagRecording', 'CHECKBOX', null, null, null, null, 'false'),
(1508, 'zoomFeatureFlagTileView', 'CHECKBOX', null, null, null, null, 'false'),
(1509, 'zoomRoom', 'TEXT_FIELD', null, null, null, null, ''),
(1510, 'zoomServerURL', 'TEXT_FIELD', null, null, null, null, ''),
(1511, 'zoomSubject', 'TEXT_FIELD', null, null, null, null, ''),
(1512, 'zoomToken', 'TEXT_FIELD', null, null, null, null, ''),
(1513, 'zoomUserInfoAvatarURL', 'TEXT_FIELD', null, null, null, null, ''),
(1514, 'zoomUserInfoDisplayName', 'TEXT_FIELD', null, null, null, null, ''),
(1515, 'zoomUserInfoEMail', 'TEXT_FIELD', null, null, null, null, ''),
(1516, 'zoomVideoMuted', 'CHECKBOX', null, null, null, null, 'false'),
(1530, 'zoomReceiveAudio', 'CHECKBOX', null, null, null, null, 'false'),
(1531, 'zoomReceiveVideo', 'CHECKBOX', null, null, null, null, 'false'),
(1532, 'zoomSendAudio', 'CHECKBOX', null, null, null, null, 'true'),
(1533, 'zoomSendVideo', 'CHECKBOX', null, null, null, null, 'true')
;

View file

@ -0,0 +1,59 @@
UPDATE orientation SET group_id='[proctoring|jitsi]' WHERE config_attribute_id='1102';
UPDATE orientation SET group_id='jitsi_features[proctoring|jitsi]' WHERE config_attribute_id='1103';
UPDATE orientation SET group_id='jitsi_features[proctoring|jitsi]' WHERE config_attribute_id='1106';
UPDATE orientation SET group_id='jitsi_features[proctoring|jitsi]' WHERE config_attribute_id='1108';
UPDATE orientation SET group_id='jitsi_features[proctoring|jitsi]' WHERE config_attribute_id='1104';
UPDATE orientation SET group_id='jitsi_features[proctoring|jitsi]' WHERE config_attribute_id='1105';
UPDATE orientation SET group_id='jitsi_controls[proctoring|jitsi]' WHERE config_attribute_id='1100';
UPDATE orientation SET group_id='jitsi_controls[proctoring|jitsi]' WHERE config_attribute_id='1116';
UPDATE orientation SET group_id='jitsi_controls[proctoring|jitsi]' WHERE config_attribute_id='1101';
UPDATE orientation SET group_id='jitsi_audio_video[proctoring|jitsi]' WHERE config_attribute_id='1130';
UPDATE orientation SET group_id='jitsi_audio_video[proctoring|jitsi]' WHERE config_attribute_id='1131';
UPDATE orientation SET group_id='jitsi_audio_video[proctoring|jitsi]' WHERE config_attribute_id='1132';
UPDATE orientation SET group_id='jitsi_audio_video[proctoring|jitsi]' WHERE config_attribute_id='1133';
INSERT IGNORE INTO configuration_attribute VALUES
(1500, 'zoomEnable', 'CHECKBOX', null, null, null, null, 'false'),
(1501, 'zoomAudioOnly', 'CHECKBOX', null, null, null, null, 'false'),
(1502, 'zoomAudioMuted', 'CHECKBOX', null, null, null, null, 'true'),
(1503, 'zoomFeatureFlagChat', 'CHECKBOX', null, null, null, null, 'false'),
(1504, 'zoomFeatureFlagCloseCaptions', 'CHECKBOX', null, null, null, null, 'false'),
(1505, 'zoomFeatureFlagDisplayMeetingName', 'CHECKBOX', null, null, null, null, 'false'),
(1506, 'zoomFeatureFlagRaiseHand', 'CHECKBOX', null, null, null, null, 'false'),
(1507, 'zoomFeatureFlagRecording', 'CHECKBOX', null, null, null, null, 'false'),
(1508, 'zoomFeatureFlagTileView', 'CHECKBOX', null, null, null, null, 'false'),
(1509, 'zoomRoom', 'TEXT_FIELD', null, null, null, null, ''),
(1510, 'zoomServerURL', 'TEXT_FIELD', null, null, null, null, ''),
(1511, 'zoomSubject', 'TEXT_FIELD', null, null, null, null, ''),
(1512, 'zoomToken', 'TEXT_FIELD', null, null, null, null, ''),
(1513, 'zoomUserInfoAvatarURL', 'TEXT_FIELD', null, null, null, null, ''),
(1514, 'zoomUserInfoDisplayName', 'TEXT_FIELD', null, null, null, null, ''),
(1515, 'zoomUserInfoEMail', 'TEXT_FIELD', null, null, null, null, ''),
(1516, 'zoomVideoMuted', 'CHECKBOX', null, null, null, null, 'false'),
(1530, 'zoomReceiveAudio', 'CHECKBOX', null, null, null, null, 'false'),
(1531, 'zoomReceiveVideo', 'CHECKBOX', null, null, null, null, 'false'),
(1532, 'zoomSendAudio', 'CHECKBOX', null, null, null, null, 'true'),
(1533, 'zoomSendVideo', 'CHECKBOX', null, null, null, null, 'true')
;
SET @proct_view_id = (SELECT id FROM view WHERE name='proctoring');
INSERT IGNORE INTO orientation (config_attribute_id, template_id, view_id, group_id, x_position, y_position, width, height, title) VALUES
(1500, 0, @proct_view_id, '[proctoring|Zoom]', 6, 1, 6, 1, 'NONE'),
(1503, 0, @proct_view_id, 'zoom_features[proctoring|Zoom]', 6, 7, 6, 1, 'NONE'),
(1506, 0, @proct_view_id, 'zoom_features[proctoring|Zoom]', 6, 8, 6, 1, 'NONE'),
(1508, 0, @proct_view_id, 'zoom_features[proctoring|Zoom]', 6, 9, 6, 1, 'NONE'),
(1504, 0, @proct_view_id, 'zoom_features[proctoring|Zoom]', 6, 10, 6, 1, 'NONE'),
(1505, 0, @proct_view_id, 'zoom_features[proctoring|Zoom]', 6, 11, 6, 1, 'NONE'),
(1502, 0, @proct_view_id, 'zoom_controls[proctoring|Zoom]', 6, 13, 6, 1, 'NONE'),
(1516, 0, @proct_view_id, 'zoom_controls[proctoring|Zoom]', 6, 14, 6, 1, 'NONE'),
(1501, 0, @proct_view_id, 'zoom_controls[proctoring|Zoom]', 6, 15, 6, 1, 'NONE'),
(1530, 0, @proct_view_id, 'zoom_audio_video[proctoring|Zoom]', 6, 2, 6, 1, 'NONE'),
(1531, 0, @proct_view_id, 'zoom_audio_video[proctoring|Zoom]', 6, 3, 6, 1, 'NONE'),
(1532, 0, @proct_view_id, 'zoom_audio_video[proctoring|Zoom]', 6, 4, 6, 1, 'NONE'),
(1533, 0, @proct_view_id, 'zoom_audio_video[proctoring|Zoom]', 6, 5, 6, 1, 'NONE')
;

View file

@ -1300,6 +1300,8 @@ sebserver.examconfig.props.label.enableF10=Enable F10
sebserver.examconfig.props.label.enableF11=Enable F11
sebserver.examconfig.props.label.enableF12=Enable F12
sebserver.examconfig.props.group.jitsi=Jitsi Meet Service Settings
sebserver.examconfig.props.group.jitsi.tooltip=Settings used with a Jitsi Meet service for proctoring
sebserver.examconfig.props.group.jitsi_audio_video=Jitsi Meet Audio Video Settings
sebserver.examconfig.props.group.jitsi_audio_video.tooltip=
sebserver.examconfig.props.group.jitsi_features=Jitsi Meet Features
@ -1383,6 +1385,62 @@ sebserver.examconfig.props.label.remoteProctoringViewShow.2.tooltip=
sebserver.examconfig.props.label.remoteProctoringViewShow.3=Always
sebserver.examconfig.props.label.remoteProctoringViewShow.3.tooltip=
sebserver.examconfig.props.group.Zoom=Zoom Service Settings
sebserver.examconfig.props.group.Zoom.tooltip=Settings used with a Zoom Meeting service for proctoring
sebserver.examconfig.props.group.zoom_audio_video=Zoom Audio Video Settings
sebserver.examconfig.props.group.zoom_audio_video.tooltip=
sebserver.examconfig.props.group.zoom_features=Zoom Features
sebserver.examconfig.props.group.zoom_features.tooltip=
sebserver.examconfig.props.group.zoom_controls=Zoom User Controls
sebserver.examconfig.props.group.zoom_controls.tooltip=When the proctoring view is disabled (see its display policy on left), users can mute and unmute audio and video manually.<br/>Audio and video streams can be disabled globally with the settings below.
sebserver.examconfig.props.label.zoomAudioMuted=Audio Initially Muted
sebserver.examconfig.props.label.zoomAudioMuted.tooltip=
sebserver.examconfig.props.label.zoomAudioOnly=Audio Only
sebserver.examconfig.props.label.zoomAudioOnly.tooltip=
sebserver.examconfig.props.label.zoomEnable=Enable Zoom
sebserver.examconfig.props.label.zoomEnable.tooltip=
sebserver.examconfig.props.label.zoomFeatureFlagChat=Enable Chat
sebserver.examconfig.props.label.zoomFeatureFlagChat.tooltip=
sebserver.examconfig.props.label.zoomFeatureFlagCloseCaptions=Enable Close Captions
sebserver.examconfig.props.label.zoomFeatureFlagCloseCaptions.tooltip=
sebserver.examconfig.props.label.zoomFeatureFlagDisplayingName=Display Meeting Name
sebserver.examconfig.props.label.zoomFeatureFlagDisplayMeetingName.tooltip
sebserver.examconfig.props.label.zoomFeatureFlagRaiseHand=Enable Raise Hand
sebserver.examconfig.props.label.zoomFeatureFlagRaiseHand.tooltip=
sebserver.examconfig.props.label.zoomFeatureFlagRecording=Allow Recording
sebserver.examconfig.props.label.zoomFeatureFlagRecording.tooltip=
sebserver.examconfig.props.label.zoomFeatureFlagTileView=Allow Tile View
sebserver.examconfig.props.label.zoomFeatureFlagTileView.tooltip=Note: Disabling Allow Tile View is not yet functional in this version.
sebserver.examconfig.props.label.zoomRoom=Room
sebserver.examconfig.props.label.zoomRoom.tooltip=
sebserver.examconfig.props.label.zoomServerURL=Server URL
sebserver.examconfig.props.label.zoomServerURL.tooltip=
sebserver.examconfig.props.label.zoomSubject=Subject
sebserver.examconfig.props.label.zoomSubject.tooltip=
sebserver.examconfig.props.label.zoomToken=Token
sebserver.examconfig.props.label.zoomToken.tooltip=
sebserver.examconfig.props.label.zoomUserInfoAvatarURL=Avatar URL
sebserver.examconfig.props.label.zoomUserInfoAvatarURL.tooltip=
sebserver.examconfig.props.label.zoomUserInfoDisplayName=Display Name
sebserver.examconfig.props.label.zoomUserInfoDisplayName.tooltip=
sebserver.examconfig.props.label.zoomUserInfoEMail=Info Mail
sebserver.examconfig.props.label.zoomUserInfoEMail.tooltip=
sebserver.examconfig.props.label.zoomVideoMuted=Video Initially Muted
sebserver.examconfig.props.label.zoomVideoMuted.tooltip=
sebserver.examconfig.props.label.zoomReceiveAudio=Receive Audio
sebserver.examconfig.props.label.zoomReceiveAudio.tooltip=Global settings for receiving and sending audio/video streams.<br/>Streams can also be enabled/disabled by SEB Server during the exam session.
sebserver.examconfig.props.label.zoomReceiveVideo=Receive Video
sebserver.examconfig.props.label.zoomReceiveVideo.tooltip=Global settings for receiving and sending audio/video streams.<br/>Streams can also be enabled/disabled by SEB Server during the exam session.
sebserver.examconfig.props.label.zoomSendAudio=Send Audio
sebserver.examconfig.props.label.zoomSendAudio.tooltip=Global settings for receiving and sending audio/video streams.<br/>Streams can also be enabled/disabled by SEB Server during the exam session.
sebserver.examconfig.props.label.zoomSendVideo=Send Video
sebserver.examconfig.props.label.zoomSendVideo.tooltip=Global settings for receiving and sending audio/video streams.<br/>Streams can also be enabled/disabled by SEB Server during the exam session.
sebserver.examconfig.props.label.showProctoringViewButton=Show Proctoring Button
sebserver.examconfig.props.label.showProctoringViewButton

View file

@ -944,7 +944,50 @@ Table-GridLine:vertical, Table-GridLine:header, Table-GridLine:horizontal:rowtem
}
/* ExpandBar default theme */
ExpandBar {
color: #FFFFFF;
background-color: white;
border: none;
}
ExpandBar[BORDER] {
border: none;
}
ExpandItem {
color: #FFFFFF;
border: none;
}
ExpandItem-Header {
border: none;
cursor: pointer;
background-color: #595959;
background-gradient-color: #595959;
background-image: gradient( linear, left top, left bottom, from( #595959 ), to( #595959 ) );
text-shadow: none;
}
ExpandItem-Header:disabled {
cursor: default;
}
ExpandItem-Button {
background-image: url( static/images/expand.png );
}
ExpandItem-Button:hover {
background-image:
url( static/images/expand.png );
}
ExpandItem-Button:expanded {
background-image:
url( static/images/collapse.png );
}
ExpandItem-Button:expanded:hover {
background-image:
url( static/images/collapse.png );
}

View file

@ -803,6 +803,53 @@ Table-GridLine:vertical, Table-GridLine:header, Table-GridLine:horizontal:rowtem
color: transparent;
}
/* ExpandBar default theme */
ExpandBar {
color: #FFFFFF;
background-color: white;
border: none;
}
ExpandBar[BORDER] {
border: none;
}
ExpandItem {
color: #FFFFFF;
border: none;
}
ExpandItem-Header {
border: none;
cursor: pointer;
background-color: #595959;
background-gradient-color: #595959;
background-image: gradient( linear, left top, left bottom, from( #595959 ), to( #595959 ) );
text-shadow: none;
}
ExpandItem-Header:disabled {
cursor: default;
}
ExpandItem-Button {
background-image: url( static/images/expand.png );
}
ExpandItem-Button:hover {
background-image:
url( static/images/expand.png );
}
ExpandItem-Button:expanded {
background-image:
url( static/images/collapse.png );
}
ExpandItem-Button:expanded:hover {
background-image:
url( static/images/collapse.png );
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B