mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-24 08:30:27 +00:00
Reformat
This commit is contained in:
parent
9b20fe7e8e
commit
ecdf5119b0
17 changed files with 64 additions and 47 deletions
|
@ -36,9 +36,10 @@ public class BrowserFullSessionModel extends BrowserAbstractSessionModel<Browser
|
||||||
static {
|
static {
|
||||||
DEFAULT.getSessionEntries().add(new BrowserHistoryTabModel(DEFAULT));
|
DEFAULT.getSessionEntries().add(new BrowserHistoryTabModel(DEFAULT));
|
||||||
if (AppPrefs.get().pinLocalMachineOnStartup().get()) {
|
if (AppPrefs.get().pinLocalMachineOnStartup().get()) {
|
||||||
var tab = new BrowserFileSystemTabModel(DEFAULT, DataStorage.get().local().ref(), BrowserFileSystemTabModel.SelectionMode.ALL);
|
var tab = new BrowserFileSystemTabModel(
|
||||||
|
DEFAULT, DataStorage.get().local().ref(), BrowserFileSystemTabModel.SelectionMode.ALL);
|
||||||
ThreadHelper.runFailableAsync(() -> {
|
ThreadHelper.runFailableAsync(() -> {
|
||||||
DEFAULT.openSync(tab,null);
|
DEFAULT.openSync(tab, null);
|
||||||
DEFAULT.pinTab(tab);
|
DEFAULT.pinTab(tab);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -134,7 +135,9 @@ public class BrowserFullSessionModel extends BrowserAbstractSessionModel<Browser
|
||||||
|
|
||||||
globalPinnedTab.setValue(tab);
|
globalPinnedTab.setValue(tab);
|
||||||
|
|
||||||
var previousOthers = previousTabs.stream().filter(browserSessionTab -> browserSessionTab != tab).toList();
|
var previousOthers = previousTabs.stream()
|
||||||
|
.filter(browserSessionTab -> browserSessionTab != tab)
|
||||||
|
.toList();
|
||||||
if (previousOthers.size() > 0) {
|
if (previousOthers.size() > 0) {
|
||||||
var prev = previousOthers.getLast();
|
var prev = previousOthers.getLast();
|
||||||
getSelectedEntry().setValue(prev);
|
getSelectedEntry().setValue(prev);
|
||||||
|
|
|
@ -9,8 +9,8 @@ import io.xpipe.app.comp.augment.ContextMenuAugment;
|
||||||
import io.xpipe.app.comp.base.*;
|
import io.xpipe.app.comp.base.*;
|
||||||
import io.xpipe.app.core.AppFont;
|
import io.xpipe.app.core.AppFont;
|
||||||
import io.xpipe.app.util.InputHelper;
|
import io.xpipe.app.util.InputHelper;
|
||||||
|
|
||||||
import io.xpipe.app.util.PlatformThread;
|
import io.xpipe.app.util.PlatformThread;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
@ -99,13 +99,17 @@ public class BrowserFileSystemTabComp extends SimpleComp {
|
||||||
|
|
||||||
if (model.getBrowserModel() instanceof BrowserFullSessionModel fullSessionModel) {
|
if (model.getBrowserModel() instanceof BrowserFullSessionModel fullSessionModel) {
|
||||||
var pinButton = new Button();
|
var pinButton = new Button();
|
||||||
pinButton.graphicProperty().bind(PlatformThread.sync(Bindings.createObjectBinding(() -> {
|
pinButton
|
||||||
|
.graphicProperty()
|
||||||
|
.bind(PlatformThread.sync(Bindings.createObjectBinding(
|
||||||
|
() -> {
|
||||||
if (fullSessionModel.getGlobalPinnedTab().getValue() != model) {
|
if (fullSessionModel.getGlobalPinnedTab().getValue() != model) {
|
||||||
return new FontIcon("mdi2p-pin");
|
return new FontIcon("mdi2p-pin");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FontIcon("mdi2p-pin-off");
|
return new FontIcon("mdi2p-pin-off");
|
||||||
}, fullSessionModel.getGlobalPinnedTab())));
|
},
|
||||||
|
fullSessionModel.getGlobalPinnedTab())));
|
||||||
pinButton.setOnAction(e -> {
|
pinButton.setOnAction(e -> {
|
||||||
if (fullSessionModel.getGlobalPinnedTab().getValue() != model) {
|
if (fullSessionModel.getGlobalPinnedTab().getValue() != model) {
|
||||||
fullSessionModel.pinTab(model);
|
fullSessionModel.pinTab(model);
|
||||||
|
|
|
@ -114,7 +114,8 @@ public final class BrowserFileSystemTabModel extends BrowserStoreSessionTab<File
|
||||||
|
|
||||||
var current = getCurrentDirectory();
|
var current = getCurrentDirectory();
|
||||||
// We might close this after storage shutdown
|
// We might close this after storage shutdown
|
||||||
if (DataStorage.get() != null && DataStorage.get().getStoreEntries().contains(getEntry().get())
|
if (DataStorage.get() != null
|
||||||
|
&& DataStorage.get().getStoreEntries().contains(getEntry().get())
|
||||||
&& savedState != null
|
&& savedState != null
|
||||||
&& current != null) {
|
&& current != null) {
|
||||||
savedState.cd(current.getPath(), false);
|
savedState.cd(current.getPath(), false);
|
||||||
|
|
|
@ -11,9 +11,9 @@ import io.xpipe.app.storage.DataColor;
|
||||||
import io.xpipe.app.terminal.TerminalDockComp;
|
import io.xpipe.app.terminal.TerminalDockComp;
|
||||||
import io.xpipe.app.terminal.TerminalDockModel;
|
import io.xpipe.app.terminal.TerminalDockModel;
|
||||||
import io.xpipe.app.terminal.TerminalView;
|
import io.xpipe.app.terminal.TerminalView;
|
||||||
|
|
||||||
import io.xpipe.app.terminal.WindowsTerminalType;
|
import io.xpipe.app.terminal.WindowsTerminalType;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.value.ObservableBooleanValue;
|
import javafx.beans.value.ObservableBooleanValue;
|
||||||
|
@ -90,7 +90,9 @@ public final class BrowserTerminalDockTabModel extends BrowserSessionTab {
|
||||||
// Ugly fix for Windows Terminal instances not closing properly if multiple windows exist
|
// Ugly fix for Windows Terminal instances not closing properly if multiple windows exist
|
||||||
if (AppPrefs.get().terminalType().getValue() instanceof WindowsTerminalType) {
|
if (AppPrefs.get().terminalType().getValue() instanceof WindowsTerminalType) {
|
||||||
var sessions = TerminalView.get().getSessions();
|
var sessions = TerminalView.get().getSessions();
|
||||||
var others = sessions.stream().filter(shellSession -> shellSession.getTerminal().equals(session.getTerminal())).count();
|
var others = sessions.stream()
|
||||||
|
.filter(shellSession -> shellSession.getTerminal().equals(session.getTerminal()))
|
||||||
|
.count();
|
||||||
if (others == 0) {
|
if (others == 0) {
|
||||||
session.getTerminal().controllable().ifPresent(controllableTerminalSession -> {
|
session.getTerminal().controllable().ifPresent(controllableTerminalSession -> {
|
||||||
controllableTerminalSession.close();
|
controllableTerminalSession.close();
|
||||||
|
|
|
@ -38,14 +38,21 @@ public class SideMenuBarComp extends Comp<CompStructure<VBox>> {
|
||||||
|
|
||||||
var selectedBorder = Bindings.createObjectBinding(
|
var selectedBorder = Bindings.createObjectBinding(
|
||||||
() -> {
|
() -> {
|
||||||
var c = Platform.getPreferences().getAccentColor().desaturate().desaturate();
|
var c = Platform.getPreferences()
|
||||||
|
.getAccentColor()
|
||||||
|
.desaturate()
|
||||||
|
.desaturate();
|
||||||
return new Background(new BackgroundFill(c, new CornerRadii(8), new Insets(14, 1, 14, 2)));
|
return new Background(new BackgroundFill(c, new CornerRadii(8), new Insets(14, 1, 14, 2)));
|
||||||
},
|
},
|
||||||
Platform.getPreferences().accentColorProperty());
|
Platform.getPreferences().accentColorProperty());
|
||||||
|
|
||||||
var hoverBorder = Bindings.createObjectBinding(
|
var hoverBorder = Bindings.createObjectBinding(
|
||||||
() -> {
|
() -> {
|
||||||
var c = Platform.getPreferences().getAccentColor().darker().desaturate().desaturate();
|
var c = Platform.getPreferences()
|
||||||
|
.getAccentColor()
|
||||||
|
.darker()
|
||||||
|
.desaturate()
|
||||||
|
.desaturate();
|
||||||
return new Background(new BackgroundFill(c, new CornerRadii(8), new Insets(14, 1, 14, 2)));
|
return new Background(new BackgroundFill(c, new CornerRadii(8), new Insets(14, 1, 14, 2)));
|
||||||
},
|
},
|
||||||
Platform.getPreferences().accentColorProperty());
|
Platform.getPreferences().accentColorProperty());
|
||||||
|
|
|
@ -100,7 +100,10 @@ public class StandardStoreEntryComp extends StoreEntryComp {
|
||||||
information.setGraphicTextGap(7);
|
information.setGraphicTextGap(7);
|
||||||
if (getWrapper().getEntry().getProvider() != null) {
|
if (getWrapper().getEntry().getProvider() != null) {
|
||||||
try {
|
try {
|
||||||
information.textProperty().bind(PlatformThread.sync(getWrapper().getEntry().getProvider().informationString(section)));
|
information
|
||||||
|
.textProperty()
|
||||||
|
.bind(PlatformThread.sync(
|
||||||
|
getWrapper().getEntry().getProvider().informationString(section)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ErrorEvent.fromThrowable(e).handle();
|
ErrorEvent.fromThrowable(e).handle();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import io.xpipe.app.core.AppActionLinkDetector;
|
||||||
import io.xpipe.app.core.AppFont;
|
import io.xpipe.app.core.AppFont;
|
||||||
import io.xpipe.app.core.AppI18n;
|
import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.ext.ActionProvider;
|
import io.xpipe.app.ext.ActionProvider;
|
||||||
import io.xpipe.app.issue.ErrorEvent;
|
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
import io.xpipe.app.prefs.AppPrefs;
|
||||||
import io.xpipe.app.resources.AppResources;
|
import io.xpipe.app.resources.AppResources;
|
||||||
import io.xpipe.app.storage.DataColor;
|
import io.xpipe.app.storage.DataColor;
|
||||||
|
@ -24,9 +23,7 @@ import io.xpipe.app.update.XPipeDistributionType;
|
||||||
import io.xpipe.app.util.*;
|
import io.xpipe.app.util.*;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
|
||||||
import javafx.beans.value.ObservableDoubleValue;
|
import javafx.beans.value.ObservableDoubleValue;
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.css.PseudoClass;
|
import javafx.css.PseudoClass;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
|
|
|
@ -157,7 +157,8 @@ public class StoreEntryWrapper {
|
||||||
|
|
||||||
busy.setValue(entry.getBusyCounter().get() != 0);
|
busy.setValue(entry.getBusyCounter().get() != 0);
|
||||||
deletable.setValue(entry.getConfiguration().isDeletable()
|
deletable.setValue(entry.getConfiguration().isDeletable()
|
||||||
|| (AppPrefs.get().developerMode().getValue() && AppPrefs.get().developerDisableGuiRestrictions().getValue()));
|
|| (AppPrefs.get().developerMode().getValue()
|
||||||
|
&& AppPrefs.get().developerDisableGuiRestrictions().getValue()));
|
||||||
sessionActive.setValue(entry.getStore() instanceof SingletonSessionStore<?> ss
|
sessionActive.setValue(entry.getStore() instanceof SingletonSessionStore<?> ss
|
||||||
&& entry.getStore() instanceof ShellStore
|
&& entry.getStore() instanceof ShellStore
|
||||||
&& ss.isSessionRunning());
|
&& ss.isSessionRunning());
|
||||||
|
|
|
@ -29,9 +29,10 @@ public class AppHomebrewCoreutilsCheck {
|
||||||
|
|
||||||
var loc = checkCoreutils();
|
var loc = checkCoreutils();
|
||||||
if (loc.isPresent()) {
|
if (loc.isPresent()) {
|
||||||
ErrorEvent.fromMessage("You have the homebrew coreutils package installed and added to your PATH at " + loc.get() + "." +
|
ErrorEvent.fromMessage("You have the homebrew coreutils package installed and added to your PATH at "
|
||||||
" The coreutils commands overwrite and are incompatible to the native macOS commands, which XPipe expects." +
|
+ loc.get() + "."
|
||||||
" Please remove the coreutils commands from your PATH prior to launching XPipe.")
|
+ " The coreutils commands overwrite and are incompatible to the native macOS commands, which XPipe expects."
|
||||||
|
+ " Please remove the coreutils commands from your PATH prior to launching XPipe.")
|
||||||
.term()
|
.term()
|
||||||
.handle();
|
.handle();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.xpipe.app.core.check;
|
package io.xpipe.app.core.check;
|
||||||
|
|
||||||
import io.xpipe.app.core.AppProperties;
|
|
||||||
import io.xpipe.app.issue.ErrorEvent;
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
|
@ -4,7 +4,6 @@ import io.xpipe.app.beacon.AppBeaconServer;
|
||||||
import io.xpipe.app.core.*;
|
import io.xpipe.app.core.*;
|
||||||
import io.xpipe.app.core.check.AppDebugModeCheck;
|
import io.xpipe.app.core.check.AppDebugModeCheck;
|
||||||
import io.xpipe.app.core.check.AppTempCheck;
|
import io.xpipe.app.core.check.AppTempCheck;
|
||||||
import io.xpipe.app.core.check.AppUserDirectoryCheck;
|
|
||||||
import io.xpipe.app.core.launcher.LauncherCommand;
|
import io.xpipe.app.core.launcher.LauncherCommand;
|
||||||
import io.xpipe.app.core.window.ModifiedStage;
|
import io.xpipe.app.core.window.ModifiedStage;
|
||||||
import io.xpipe.app.issue.*;
|
import io.xpipe.app.issue.*;
|
||||||
|
|
|
@ -15,7 +15,6 @@ import io.xpipe.core.process.OsType;
|
||||||
import io.xpipe.core.util.InPlaceSecretValue;
|
import io.xpipe.core.util.InPlaceSecretValue;
|
||||||
import io.xpipe.core.util.ModuleHelper;
|
import io.xpipe.core.util.ModuleHelper;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.value.ObservableBooleanValue;
|
import javafx.beans.value.ObservableBooleanValue;
|
||||||
import javafx.beans.value.ObservableDoubleValue;
|
import javafx.beans.value.ObservableDoubleValue;
|
||||||
|
@ -43,8 +42,7 @@ public class AppPrefs {
|
||||||
@Getter
|
@Getter
|
||||||
private final BooleanProperty requiresRestart = new SimpleBooleanProperty(false);
|
private final BooleanProperty requiresRestart = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
final BooleanProperty pinLocalMachineOnStartup =
|
final BooleanProperty pinLocalMachineOnStartup = map(Mapping.builder()
|
||||||
map(Mapping.builder()
|
|
||||||
.property(new SimpleBooleanProperty(false))
|
.property(new SimpleBooleanProperty(false))
|
||||||
.key("pinLocalMachineOnStartup")
|
.key("pinLocalMachineOnStartup")
|
||||||
.valueClass(Boolean.class)
|
.valueClass(Boolean.class)
|
||||||
|
|
|
@ -23,8 +23,7 @@ public class FileBrowserCategory extends AppPrefsCategory {
|
||||||
.pref(prefs.downloadsDirectory)
|
.pref(prefs.downloadsDirectory)
|
||||||
.addString(prefs.downloadsDirectory)
|
.addString(prefs.downloadsDirectory)
|
||||||
.pref(prefs.pinLocalMachineOnStartup)
|
.pref(prefs.pinLocalMachineOnStartup)
|
||||||
.addToggle(prefs.pinLocalMachineOnStartup)
|
.addToggle(prefs.pinLocalMachineOnStartup))
|
||||||
)
|
|
||||||
.buildComp();
|
.buildComp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,7 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
|
||||||
ExternalTerminalType WINDOWS_TERMINAL_CANARY = new Canary();
|
ExternalTerminalType WINDOWS_TERMINAL_CANARY = new Canary();
|
||||||
|
|
||||||
private static CommandBuilder toCommand(TerminalLaunchConfiguration configuration) throws Exception {
|
private static CommandBuilder toCommand(TerminalLaunchConfiguration configuration) throws Exception {
|
||||||
var cmd = CommandBuilder.of()
|
var cmd = CommandBuilder.of().addIf(configuration.isPreferTabs(), "-w", "1", "nt");
|
||||||
.addIf(configuration.isPreferTabs(), "-w", "1", "nt");
|
|
||||||
|
|
||||||
if (configuration.getColor() != null) {
|
if (configuration.getColor() != null) {
|
||||||
cmd.add("--tabColor").addQuoted(configuration.getColor().toHexString());
|
cmd.add("--tabColor").addQuoted(configuration.getColor().toHexString());
|
||||||
|
|
|
@ -94,12 +94,16 @@ public class AppInstaller {
|
||||||
: getPowershellCommand(file.toString(), logFile, exec, systemWide);
|
: getPowershellCommand(file.toString(), logFile, exec, systemWide);
|
||||||
String toRun;
|
String toRun;
|
||||||
if (ProcessControlProvider.get().getEffectiveLocalDialect() == ShellDialects.CMD) {
|
if (ProcessControlProvider.get().getEffectiveLocalDialect() == ShellDialects.CMD) {
|
||||||
toRun = systemWide ? "powershell -Command Start-Process -Verb runAs -WindowStyle Minimized -FilePath cmd -ArgumentList \"/c\", '\""
|
toRun = systemWide
|
||||||
+ ScriptHelper.createLocalExecScript(command) + "\"'" :
|
? "powershell -Command Start-Process -Verb runAs -WindowStyle Minimized -FilePath cmd -ArgumentList \"/c\", '\""
|
||||||
"start \"XPipe Updater\" /min cmd /c \"" + ScriptHelper.createLocalExecScript(command) + "\"";
|
+ ScriptHelper.createLocalExecScript(command) + "\"'"
|
||||||
|
: "start \"XPipe Updater\" /min cmd /c \"" + ScriptHelper.createLocalExecScript(command)
|
||||||
|
+ "\"";
|
||||||
} else {
|
} else {
|
||||||
toRun = "Start-Process -WindowStyle Minimized -FilePath powershell -ArgumentList \"-ExecutionPolicy\", \"Bypass\", \"-File\", \"`\""
|
toRun =
|
||||||
+ ScriptHelper.createLocalExecScript(command) + "`\"\"" + (systemWide ? " -Verb runAs" : "");
|
"Start-Process -WindowStyle Minimized -FilePath powershell -ArgumentList \"-ExecutionPolicy\", \"Bypass\", \"-File\", \"`\""
|
||||||
|
+ ScriptHelper.createLocalExecScript(command) + "`\"\""
|
||||||
|
+ (systemWide ? " -Verb runAs" : "");
|
||||||
}
|
}
|
||||||
runAndClose(() -> {
|
runAndClose(() -> {
|
||||||
LocalShell.getShell().executeSimpleCommand(toRun);
|
LocalShell.getShell().executeSimpleCommand(toRun);
|
||||||
|
@ -112,7 +116,8 @@ public class AppInstaller {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSystemWide() {
|
private boolean isSystemWide() {
|
||||||
return Files.exists(XPipeInstallation.getCurrentInstallationBasePath().resolve("system"));
|
return Files.exists(
|
||||||
|
XPipeInstallation.getCurrentInstallationBasePath().resolve("system"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCmdCommand(String file, String logFile, String exec, boolean systemWide) {
|
private String getCmdCommand(String file, String logFile, String exec, boolean systemWide) {
|
||||||
|
|
|
@ -260,7 +260,7 @@ public class XPipeInstallation {
|
||||||
String path;
|
String path;
|
||||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||||
var pg = System.getenv("ProgramFiles");
|
var pg = System.getenv("ProgramFiles");
|
||||||
var systemPath = Path.of(pg,stage ? "XPipe PTB" : "XPipe");
|
var systemPath = Path.of(pg, stage ? "XPipe PTB" : "XPipe");
|
||||||
if (Files.exists(systemPath)) {
|
if (Files.exists(systemPath)) {
|
||||||
return systemPath.toString();
|
return systemPath.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,15 @@ import io.xpipe.app.browser.action.BrowserLeafAction;
|
||||||
import io.xpipe.app.browser.file.BrowserEntry;
|
import io.xpipe.app.browser.file.BrowserEntry;
|
||||||
import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
|
import io.xpipe.app.browser.file.BrowserFileSystemTabModel;
|
||||||
import io.xpipe.app.core.AppI18n;
|
import io.xpipe.app.core.AppI18n;
|
||||||
import io.xpipe.app.prefs.AppPrefs;
|
|
||||||
import io.xpipe.core.store.FileKind;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyCodeCombination;
|
import javafx.scene.input.KeyCodeCombination;
|
||||||
import javafx.scene.input.KeyCombination;
|
import javafx.scene.input.KeyCombination;
|
||||||
|
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DownloadAction implements BrowserLeafAction {
|
public class DownloadAction implements BrowserLeafAction {
|
||||||
|
|
Loading…
Reference in a new issue