All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.teamapps.ux.component.field.upload.FileField Maven / Gradle / Ivy

There is a newer version: 0.9.194
Show newest version
/*-
 * ========================LICENSE_START=================================
 * TeamApps
 * ---
 * Copyright (C) 2014 - 2023 TeamApps.org
 * ---
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =========================LICENSE_END==================================
 */
package org.teamapps.ux.component.field.upload;

import org.teamapps.data.extract.BeanPropertyExtractor;
import org.teamapps.data.extract.PropertyExtractor;
import org.teamapps.data.extract.PropertyProvider;
import org.teamapps.dto.UiEvent;
import org.teamapps.dto.UiField;
import org.teamapps.dto.UiFileField;
import org.teamapps.dto.UiIdentifiableClientRecord;
import org.teamapps.event.Event;
import org.teamapps.formatter.FileSizeFormatter;
import org.teamapps.icon.material.MaterialIcon;
import org.teamapps.ux.cache.record.legacy.CacheManipulationHandle;
import org.teamapps.ux.cache.record.legacy.ClientRecordCache;
import org.teamapps.ux.component.field.AbstractField;
import org.teamapps.ux.component.template.BaseTemplate;
import org.teamapps.ux.component.template.BaseTemplateRecord;
import org.teamapps.ux.component.template.Template;
import org.teamapps.ux.i18n.TeamAppsDictionary;
import org.teamapps.ux.icon.TeamAppsIconBundle;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class FileField extends AbstractField> {


	public final Event onUploadTooLarge = new Event<>();
	public final Event onUploadStarted = new Event<>();
	public final Event onUploadCanceled = new Event<>();
	public final Event onUploadFailed = new Event<>();
	public final Event> onUploadSuccessful = new Event<>();
	public final Event onFileItemClicked = new Event<>();
	public final Event onFileItemRemoved = new Event<>();

	private FileFieldDisplayType displayType = FileFieldDisplayType.FLOATING;
	private boolean showEntriesAsButtonsOnHover = false;
	private int maxFiles = Integer.MAX_VALUE;
	/**
	 * List of "unique file type specifiers".
	 * Examples: ".png", "image/png", "image/*"
	 * See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept#unique_file_type_specifiers
	 */
	private List acceptedFileTypes = List.of();

	private long maxBytesPerFile = 10_000_000; // There is also a hard limitation! (see application.properties)
	private String uploadUrl = "/upload"; // May point anywhere.
	private Template uploadButtonTemplate = BaseTemplate.BUTTON;
	private Object uploadButtonData = new BaseTemplateRecord(getSessionContext().getIcon(TeamAppsIconBundle.UPLOAD.getKey()), getSessionContext().getLocalized(TeamAppsDictionary.UPLOAD.getKey()));
	private PropertyProvider uploadButtonPropertyProvider = new BeanPropertyExtractor<>();

	private final UploadedFileToRecordConverter uploadedFileToRecordConverter;
	private Template fileItemTemplate = BaseTemplate.FILE_ITEM_FLOATING;
	private PropertyProvider fileItemPropertyProvider = new BeanPropertyExtractor<>();
	private final ClientRecordCache recordCache = new ClientRecordCache<>(this::createUiIdentifiableClientRecord);

	public FileField(UploadedFileToRecordConverter uploadedFileToRecordConverter) {
		super();
		this.uploadedFileToRecordConverter = uploadedFileToRecordConverter;
	}

	public static FileField> create() {
		return new FileField<>(file -> new BaseTemplateRecord<>(MaterialIcon.ATTACH_FILE, file.getName(), FileSizeFormatter.humanReadableByteCount(file.getSizeInBytes(), true, 1), file));
	}

	@Override
	public UiField createUiComponent() {
		Map uploadButtonData = uploadButtonPropertyProvider.getValues(this.uploadButtonData, uploadButtonTemplate.getPropertyNames());
		UiFileField uiField = new UiFileField(fileItemTemplate.createUiTemplate(), uploadButtonTemplate.createUiTemplate(), uploadButtonData);
		mapAbstractFieldAttributesToUiField(uiField);
		uiField.setMaxBytesPerFile(maxBytesPerFile);
		uiField.setUploadUrl(uploadUrl);

		uiField.setFileTooLargeMessage(getSessionContext().getLocalized(TeamAppsDictionary.FILE_TOO_LARGE_SHORT_MESSAGE.getKey(), FileSizeFormatter.humanReadableByteCount(maxBytesPerFile, true, 1)));
		uiField.setUploadErrorMessage(getSessionContext().getLocalized(TeamAppsDictionary.UPLOAD_ERROR_MESSAGE.getKey()));

		uiField.setDisplayType(displayType.toUiFileFieldDisplayType());
		uiField.setMaxFiles(this.maxFiles);
		uiField.setAcceptedFileTypes(acceptedFileTypes);
		uiField.setShowEntriesAsButtonsOnHover(this.showEntriesAsButtonsOnHover);

		return uiField;
	}

	@Override
	public void setValue(List records) {
		this.setValue(records, true);
	}

	public void setValue(List records, boolean cancelUploads) {
		if (cancelUploads) {
			cancelUploads();
		}
		super.setValue(records);
	}

	public void cancelUploads() {
		this.queueCommandIfRendered(() -> new UiFileField.CancelAllUploadsCommand(getId()));
	}

	private UiIdentifiableClientRecord createUiIdentifiableClientRecord(RECORD record) {
		UiIdentifiableClientRecord clientRecord = new UiIdentifiableClientRecord();
		clientRecord.setValues(fileItemPropertyProvider.getValues(record, fileItemTemplate.getPropertyNames()));
		return clientRecord;
	}

	@Override
	public Object convertUxValueToUiValue(List uxValue) {
		if (uxValue == null) {
			return null;
		}
		CacheManipulationHandle> cacheResponse = recordCache.replaceRecords(uxValue);
		cacheResponse.commit(); // this is only valid here, because updates from the ui are blocked during transmission of ux values
		return cacheResponse.getAndClearResult();
	}

	@Override
	public List convertUiValueToUxValue(Object uiValues) {
		if (uiValues == null) {
			return new ArrayList<>();
		}
		List clientIds = (List) uiValues;
		return clientIds.stream()
				.map(clientId -> recordCache.getRecordByClientId(clientId))
				.collect(Collectors.toList());
	}

	@Override
	public void handleUiEvent(UiEvent event) {
		super.handleUiEvent(event);
		switch (event.getUiEventType()) {
			case UI_FILE_FIELD_UPLOAD_TOO_LARGE: {
				UiFileField.UploadTooLargeEvent tooLargeEvent = (UiFileField.UploadTooLargeEvent) event;
				this.onUploadTooLarge.fire(new UploadTooLargeEventData(tooLargeEvent.getFileName(), tooLargeEvent.getMimeType(), tooLargeEvent.getSizeInBytes()));
				break;
			}
			case UI_FILE_FIELD_UPLOAD_STARTED: {
				UiFileField.UploadStartedEvent uploadStartedEvent = (UiFileField.UploadStartedEvent) event;
				this.onUploadStarted.fire(new UploadStartedEventData(
						uploadStartedEvent.getFileName(),
						uploadStartedEvent.getMimeType(),
						uploadStartedEvent.getSizeInBytes(),
						() -> this.queueCommandIfRendered(() -> new UiFileField.CancelUploadCommand(getId(), uploadStartedEvent.getFileItemUuid()))
				));
				break;
			}
			case UI_FILE_FIELD_UPLOAD_CANCELED: {
				UiFileField.UploadCanceledEvent canceledEvent = (UiFileField.UploadCanceledEvent) event;
				this.onUploadCanceled.fire(new UploadCanceledEventData(canceledEvent.getFileName(), canceledEvent.getMimeType(), canceledEvent.getSizeInBytes()
				));
				break;
			}
			case UI_FILE_FIELD_UPLOAD_FAILED: {
				UiFileField.UploadFailedEvent failedEvent = (UiFileField.UploadFailedEvent) event;
				this.onUploadFailed.fire(new UploadFailedEventData(failedEvent.getFileName(), failedEvent.getMimeType(), failedEvent.getSizeInBytes()
				));
				break;
			}
			case UI_FILE_FIELD_UPLOAD_SUCCESSFUL: {
				UiFileField.UploadSuccessfulEvent uploadedEvent = (UiFileField.UploadSuccessfulEvent) event;
				UploadedFile uploadedFile = new UploadedFile(uploadedEvent.getUploadedFileUuid(), uploadedEvent.getFileName(), uploadedEvent.getSizeInBytes(), uploadedEvent.getMimeType(),
						() -> {
							try {
								return new FileInputStream(getSessionContext().getUploadedFileByUuid(uploadedEvent.getUploadedFileUuid()));
							} catch (FileNotFoundException e) {
								throw new UploadedFileAccessException(e);
							}
						},
						() -> getSessionContext().getUploadedFileByUuid(uploadedEvent.getUploadedFileUuid())
				);
				RECORD record = uploadedFileToRecordConverter.convert(uploadedFile);
				CacheManipulationHandle cacheResponse = recordCache.addRecord(record);
				if (isRendered()) {
					getSessionContext().queueCommand(new UiFileField.ReplaceFileItemCommand(getId(), uploadedEvent.getFileItemUuid(), cacheResponse.getAndClearResult()), aVoid -> cacheResponse.commit());
				} else {
					cacheResponse.commit();
				}
				onUploadSuccessful.fire(new UploadSuccessfulEventData<>(uploadedFile, record));
				break;
			}
			case UI_FILE_FIELD_FILE_ITEM_CLICKED: {
				UiFileField.FileItemClickedEvent fileClickedEvent = (UiFileField.FileItemClickedEvent) event;
				RECORD record = recordCache.getRecordByClientId(fileClickedEvent.getClientId());
				onFileItemClicked.fire(record);
				break;
			}
		}
	}

	@Override
	public boolean isEmptyValue(List value) {
		return value == null || value.isEmpty();
	}

	@Override
	protected void applyValueFromUi(Object value) {
		List oldValue = new ArrayList<>(getValue() != null ? getValue() : Collections.emptyList());
		super.applyValueFromUi(value);
		if (oldValue != null) {
			oldValue.removeAll(getValue() != null ? getValue() : Collections.emptyList());
			oldValue.forEach(record -> onFileItemRemoved.fire(record));
		}
	}

	public Template getFileItemTemplate() {
		return fileItemTemplate;
	}

	public void setFileItemTemplate(Template fileItemTemplate) {
		this.fileItemTemplate = fileItemTemplate;
		queueCommandIfRendered(() -> new UiFileField.SetItemTemplateCommand(getId(), fileItemTemplate.createUiTemplate()));
	}

	public long getMaxBytesPerFile() {
		return maxBytesPerFile;
	}

	public void setMaxBytesPerFile(long maxBytesPerFile) {
		this.maxBytesPerFile = maxBytesPerFile;
		queueCommandIfRendered(() -> new UiFileField.SetMaxBytesPerFileCommand(getId(), maxBytesPerFile));
	}

	public String getUploadUrl() {
		return uploadUrl;
	}

	public void setUploadUrl(String uploadUrl) {
		this.uploadUrl = uploadUrl;
		queueCommandIfRendered(() -> new UiFileField.SetUploadUrlCommand(getId(), uploadUrl));
	}

	public Template getUploadButtonTemplate() {
		return uploadButtonTemplate;
	}

	public void setUploadButtonTemplate(Template uploadButtonTemplate) {
		this.uploadButtonTemplate = uploadButtonTemplate;
		queueCommandIfRendered(() -> new UiFileField.SetUploadButtonTemplateCommand(getId(), uploadButtonTemplate.createUiTemplate()));
	}

	public Object getUploadButtonData() {
		return uploadButtonData;
	}

	public void setUploadButtonData(Object uploadButtonData) {
		this.uploadButtonData = uploadButtonData;
		queueCommandIfRendered(() -> new UiFileField.SetUploadButtonDataCommand(getId(), uploadButtonData));
	}

	public boolean isShowEntriesAsButtonsOnHover() {
		return showEntriesAsButtonsOnHover;
	}

	public void setShowEntriesAsButtonsOnHover(boolean showEntriesAsButtonsOnHover) {
		this.showEntriesAsButtonsOnHover = showEntriesAsButtonsOnHover;
		queueCommandIfRendered(() -> new UiFileField.SetShowEntriesAsButtonsOnHoverCommand(getId(), showEntriesAsButtonsOnHover));
	}

	public FileFieldDisplayType getDisplayType() {
		return displayType;
	}

	public void setDisplayType(FileFieldDisplayType displayType) {
		this.displayType = displayType;
		queueCommandIfRendered(() -> new UiFileField.SetDisplayTypeCommand(getId(), displayType.toUiFileFieldDisplayType()));
	}

	public int getMaxFiles() {
		return maxFiles;
	}

	public void setMaxFiles(int maxFiles) {
		this.maxFiles = maxFiles;
		queueCommandIfRendered(() -> new UiFileField.SetMaxFilesCommand(getId(), maxFiles));
	}

	public PropertyProvider getUploadButtonPropertyProvider() {
		return uploadButtonPropertyProvider;
	}

	public void setUploadButtonPropertyProvider(PropertyProvider propertyProvider) {
		this.uploadButtonPropertyProvider = propertyProvider;
	}

	public void setUploadButtonPropertyExtractor(PropertyExtractor propertyExtractor) {
		this.setUploadButtonPropertyProvider(propertyExtractor);
	}

	public UploadedFileToRecordConverter getUploadedFileToRecordConverter() {
		return uploadedFileToRecordConverter;
	}

	public PropertyProvider getFileItemPropertyProvider() {
		return fileItemPropertyProvider;
	}

	public void setFileItemPropertyProvider(PropertyProvider fileItemPropertyProvider) {
		this.fileItemPropertyProvider = fileItemPropertyProvider;
	}

	public void setFileItemPropertyExtractor(PropertyExtractor fileItemPropertyExtractor) {
		this.setFileItemPropertyProvider(fileItemPropertyExtractor);
	}

	public List getAcceptedFileTypes() {
		return acceptedFileTypes;
	}

	public void setAcceptedFileTypes(List acceptedFileTypes) {
		this.acceptedFileTypes = List.copyOf(acceptedFileTypes);
		queueCommandIfRendered(() -> new UiFileField.SetAcceptedFileTypesCommand(getId(), acceptedFileTypes));
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy