Working login and chats list
This commit is contained in:
parent
336a5522f1
commit
d152f1a5a1
462
install4j.install4j
Normal file
462
install4j.install4j
Normal file
@ -0,0 +1,462 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<install4j version="8.0.8" transformSequenceNumber="8">
|
||||
<directoryPresets config="/home/ubuntu/IdeaProjects/TransferBot/target" />
|
||||
<application name="TransferBot" applicationId="6797-3437-8055-9394" mediaDir="/home/ubuntu/IdeaProjects/TransferBot/target" shortName="transferbot" publisher="Cavallium" publisherWeb="https://cavallium.it" version="1.0.0" macVolumeId="8bc612c51b1b1b24" javaMinVersion="11">
|
||||
<jreBundles jdkProviderId="AdoptOpenJDK" release="openjdk15/jdk-15+36" />
|
||||
</application>
|
||||
<files>
|
||||
<mountPoints>
|
||||
<mountPoint id="157" />
|
||||
</mountPoints>
|
||||
<entries>
|
||||
<dirEntry mountPoint="157" file="/home/ubuntu/IdeaProjects/TransferBot/target/lib" entryMode="subdir" subDirectory="lib" />
|
||||
<fileEntry mountPoint="157" file="/home/ubuntu/IdeaProjects/TransferBot/target/TransferBot-1.0-SNAPSHOT.jar" />
|
||||
</entries>
|
||||
</files>
|
||||
<launchers>
|
||||
<launcher name="transferbot" id="58">
|
||||
<executable name="transferbot" executableDir="." executableMode="gui" />
|
||||
<java mainClass="it.cavallium/it.cavallium.App" mainMode="module">
|
||||
<modulePath>
|
||||
<directory location="classes" failOnError="false" />
|
||||
<archive location="TransferBot-1.0-SNAPSHOT.jar" failOnError="false" />
|
||||
<directory location="lib" failOnError="false" />
|
||||
</modulePath>
|
||||
</java>
|
||||
</launcher>
|
||||
</launchers>
|
||||
<installerGui>
|
||||
<applications>
|
||||
<application id="installer" beanClass="com.install4j.runtime.beans.applications.InstallerApplication">
|
||||
<startup>
|
||||
<screen id="1" beanClass="com.install4j.runtime.beans.screens.StartupScreen" rollbackBarrierExitCode="0">
|
||||
<actions>
|
||||
<action id="22" beanClass="com.install4j.runtime.beans.actions.misc.RequestPrivilegesAction" actionElevationType="none" rollbackBarrierExitCode="0" />
|
||||
</actions>
|
||||
</screen>
|
||||
</startup>
|
||||
<screens>
|
||||
<screen id="2" beanClass="com.install4j.runtime.beans.screens.WelcomeScreen" styleId="41" rollbackBarrierExitCode="0">
|
||||
<actions>
|
||||
<action id="7" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" rollbackBarrierExitCode="0" multiExec="true">
|
||||
<serializedBean>
|
||||
<property name="excludedVariables" type="array" elementType="string" length="1">
|
||||
<element index="0">sys.installationDir</element>
|
||||
</property>
|
||||
</serializedBean>
|
||||
<condition>context.getBooleanVariable("sys.confirmedUpdateInstallation")</condition>
|
||||
</action>
|
||||
</actions>
|
||||
<formComponents>
|
||||
<formComponent id="3" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
|
||||
<serializedBean>
|
||||
<property name="labelText" type="string">${form:welcomeMessage}</property>
|
||||
</serializedBean>
|
||||
<visibilityScript>!context.isConsole()</visibilityScript>
|
||||
</formComponent>
|
||||
<formComponent id="4" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent">
|
||||
<serializedBean>
|
||||
<property name="consoleScript">
|
||||
<object class="com.install4j.api.beans.ScriptProperty">
|
||||
<property name="value" type="string">String message = context.getMessage("ConsoleWelcomeLabel", context.getApplicationName());
|
||||
return console.askOkCancel(message, true);
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
<formComponent id="5" beanClass="com.install4j.runtime.beans.formcomponents.UpdateAlertComponent" useExternalParametrization="true" externalParametrizationName="Update Alert" externalParametrizationMode="include">
|
||||
<externalParametrizationPropertyNames>
|
||||
<propertyName>updateCheck</propertyName>
|
||||
</externalParametrizationPropertyNames>
|
||||
</formComponent>
|
||||
<formComponent id="6" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetTop="20">
|
||||
<serializedBean>
|
||||
<property name="labelText" type="string">${i18n:ClickNext}</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</screen>
|
||||
<screen id="8" beanClass="com.install4j.runtime.beans.screens.InstallationDirectoryScreen" rollbackBarrierExitCode="0">
|
||||
<condition>!context.getBooleanVariable("sys.confirmedUpdateInstallation")</condition>
|
||||
<actions>
|
||||
<action id="11" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" rollbackBarrierExitCode="0" multiExec="true">
|
||||
<serializedBean>
|
||||
<property name="excludedVariables" type="array" elementType="string" length="1">
|
||||
<element index="0">sys.installationDir</element>
|
||||
</property>
|
||||
</serializedBean>
|
||||
<condition>context.getVariable("sys.responseFile") == null</condition>
|
||||
</action>
|
||||
</actions>
|
||||
<formComponents>
|
||||
<formComponent id="9" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="25">
|
||||
<serializedBean>
|
||||
<property name="labelText" type="string">${i18n:SelectDirLabel(${compiler:sys.fullName})}</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
<formComponent id="10" beanClass="com.install4j.runtime.beans.formcomponents.InstallationDirectoryChooserComponent" useExternalParametrization="true" externalParametrizationName="Installation Directory Chooser" externalParametrizationMode="include">
|
||||
<serializedBean>
|
||||
<property name="requestFocus" type="boolean" value="true" />
|
||||
</serializedBean>
|
||||
<externalParametrizationPropertyNames>
|
||||
<propertyName>suggestAppDir</propertyName>
|
||||
<propertyName>validateApplicationId</propertyName>
|
||||
<propertyName>existingDirWarning</propertyName>
|
||||
<propertyName>checkWritable</propertyName>
|
||||
<propertyName>manualEntryAllowed</propertyName>
|
||||
<propertyName>checkFreeSpace</propertyName>
|
||||
<propertyName>showRequiredDiskSpace</propertyName>
|
||||
<propertyName>showFreeDiskSpace</propertyName>
|
||||
<propertyName>allowSpacesOnUnix</propertyName>
|
||||
<propertyName>validationScript</propertyName>
|
||||
<propertyName>standardValidation</propertyName>
|
||||
</externalParametrizationPropertyNames>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</screen>
|
||||
<screen id="12" beanClass="com.install4j.runtime.beans.screens.ComponentsScreen" rollbackBarrierExitCode="0">
|
||||
<formComponents>
|
||||
<formComponent id="13" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
|
||||
<serializedBean>
|
||||
<property name="labelText" type="string">${i18n:SelectComponentsLabel2}</property>
|
||||
</serializedBean>
|
||||
<visibilityScript>!context.isConsole()</visibilityScript>
|
||||
</formComponent>
|
||||
<formComponent id="14" beanClass="com.install4j.runtime.beans.formcomponents.ComponentSelectorComponent" useExternalParametrization="true" externalParametrizationName="Installation Components" externalParametrizationMode="include">
|
||||
<serializedBean>
|
||||
<property name="fillVertical" type="boolean" value="true" />
|
||||
</serializedBean>
|
||||
<externalParametrizationPropertyNames>
|
||||
<propertyName>selectionChangedScript</propertyName>
|
||||
</externalParametrizationPropertyNames>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</screen>
|
||||
<screen id="15" beanClass="com.install4j.runtime.beans.screens.InstallationScreen" rollbackBarrier="true" rollbackBarrierExitCode="0">
|
||||
<actions>
|
||||
<action id="17" beanClass="com.install4j.runtime.beans.actions.InstallFilesAction" actionElevationType="elevated" rollbackBarrierExitCode="0" failureStrategy="quit" errorMessage="${i18n:FileCorrupted}" />
|
||||
<action id="18" beanClass="com.install4j.runtime.beans.actions.desktop.CreateProgramGroupAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
|
||||
<serializedBean>
|
||||
<property name="uninstallerMenuName" type="string">${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}</property>
|
||||
</serializedBean>
|
||||
<condition>!context.getBooleanVariable("sys.programGroupDisabled")</condition>
|
||||
</action>
|
||||
<action id="19" beanClass="com.install4j.runtime.beans.actions.desktop.RegisterAddRemoveAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
|
||||
<serializedBean>
|
||||
<property name="itemName" type="string">${compiler:sys.fullName} ${compiler:sys.version}</property>
|
||||
</serializedBean>
|
||||
</action>
|
||||
</actions>
|
||||
<formComponents>
|
||||
<formComponent id="16" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent">
|
||||
<serializedBean>
|
||||
<property name="initialStatusMessage" type="string">${i18n:WizardPreparing}</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</screen>
|
||||
<screen id="20" beanClass="com.install4j.runtime.beans.screens.FinishedScreen" styleId="41" rollbackBarrierExitCode="0" finishScreen="true">
|
||||
<formComponents>
|
||||
<formComponent id="21" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="10">
|
||||
<serializedBean>
|
||||
<property name="labelText" type="string">${form:finishedMessage}</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</screen>
|
||||
</screens>
|
||||
</application>
|
||||
<application id="uninstaller" beanClass="com.install4j.runtime.beans.applications.UninstallerApplication">
|
||||
<serializedBean>
|
||||
<property name="customMacosExecutableName" type="string">${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}</property>
|
||||
<property name="useCustomMacosExecutableName" type="boolean" value="true" />
|
||||
</serializedBean>
|
||||
<startup>
|
||||
<screen id="23" beanClass="com.install4j.runtime.beans.screens.StartupScreen" rollbackBarrierExitCode="0">
|
||||
<actions>
|
||||
<action id="33" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" rollbackBarrierExitCode="0" />
|
||||
<action id="34" beanClass="com.install4j.runtime.beans.actions.misc.RequireInstallerPrivilegesAction" actionElevationType="none" rollbackBarrierExitCode="0" />
|
||||
</actions>
|
||||
</screen>
|
||||
</startup>
|
||||
<screens>
|
||||
<screen id="24" beanClass="com.install4j.runtime.beans.screens.UninstallWelcomeScreen" styleId="41" rollbackBarrierExitCode="0">
|
||||
<formComponents>
|
||||
<formComponent id="25" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="10">
|
||||
<serializedBean>
|
||||
<property name="labelText" type="string">${form:welcomeMessage}</property>
|
||||
</serializedBean>
|
||||
<visibilityScript>!context.isConsole()</visibilityScript>
|
||||
</formComponent>
|
||||
<formComponent id="26" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent">
|
||||
<serializedBean>
|
||||
<property name="consoleScript">
|
||||
<object class="com.install4j.api.beans.ScriptProperty">
|
||||
<property name="value" type="string">String message = context.getMessage("ConfirmUninstall", context.getApplicationName());
|
||||
return console.askYesNo(message, true);
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</screen>
|
||||
<screen id="27" beanClass="com.install4j.runtime.beans.screens.UninstallationScreen" rollbackBarrierExitCode="0">
|
||||
<actions>
|
||||
<action id="29" beanClass="com.install4j.runtime.beans.actions.UninstallFilesAction" actionElevationType="elevated" rollbackBarrierExitCode="0" />
|
||||
</actions>
|
||||
<formComponents>
|
||||
<formComponent id="28" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent">
|
||||
<serializedBean>
|
||||
<property name="initialStatusMessage" type="string">${i18n:UninstallerPreparing}</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</screen>
|
||||
<screen id="32" beanClass="com.install4j.runtime.beans.screens.UninstallFailureScreen" rollbackBarrierExitCode="0" finishScreen="true" />
|
||||
<screen id="30" beanClass="com.install4j.runtime.beans.screens.UninstallSuccessScreen" styleId="41" rollbackBarrierExitCode="0" finishScreen="true">
|
||||
<formComponents>
|
||||
<formComponent id="31" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="10">
|
||||
<serializedBean>
|
||||
<property name="labelText" type="string">${form:successMessage}</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</screen>
|
||||
</screens>
|
||||
</application>
|
||||
</applications>
|
||||
<styles defaultStyleId="35">
|
||||
<style name="Standard" id="35" beanClass="com.install4j.runtime.beans.styles.FormStyle">
|
||||
<formComponents>
|
||||
<formComponent name="Header" id="36" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" insetTop="0" insetBottom="0">
|
||||
<serializedBean>
|
||||
<property name="styleId" type="string">48</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
<group name="Main" id="37" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
|
||||
<beans>
|
||||
<formComponent id="38" beanClass="com.install4j.runtime.beans.styles.ContentComponent" insetTop="10" insetLeft="20" insetBottom="10" insetRight="20" />
|
||||
<formComponent name="Watermark" id="39" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" insetTop="0" insetLeft="5" insetBottom="0" useExternalParametrization="true" externalParametrizationName="Custom watermark" externalParametrizationMode="include">
|
||||
<serializedBean>
|
||||
<property name="enabledTitleText" type="boolean" value="false" />
|
||||
<property name="labelText" type="string">install4j</property>
|
||||
</serializedBean>
|
||||
<externalParametrizationPropertyNames>
|
||||
<propertyName>labelText</propertyName>
|
||||
</externalParametrizationPropertyNames>
|
||||
</formComponent>
|
||||
<formComponent name="Footer" id="40" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" insetTop="0" insetBottom="0">
|
||||
<serializedBean>
|
||||
<property name="styleId" type="string">52</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</beans>
|
||||
</group>
|
||||
</formComponents>
|
||||
</style>
|
||||
<style name="Banner" id="41" beanClass="com.install4j.runtime.beans.styles.FormStyle">
|
||||
<formComponents>
|
||||
<group id="42" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
|
||||
<serializedBean>
|
||||
<property name="backgroundColor">
|
||||
<object class="java.awt.Color">
|
||||
<int>255</int>
|
||||
<int>255</int>
|
||||
<int>255</int>
|
||||
<int>255</int>
|
||||
</object>
|
||||
</property>
|
||||
<property name="borderSides">
|
||||
<object class="com.install4j.runtime.beans.formcomponents.BorderSides">
|
||||
<property name="bottom" type="boolean" value="true" />
|
||||
</object>
|
||||
</property>
|
||||
<property name="imageEdgeBackgroundColor">
|
||||
<object class="java.awt.Color">
|
||||
<int>25</int>
|
||||
<int>143</int>
|
||||
<int>220</int>
|
||||
<int>255</int>
|
||||
</object>
|
||||
</property>
|
||||
<property name="imageEdgeBorder" type="boolean" value="true" />
|
||||
<property name="imageFile">
|
||||
<object class="com.install4j.api.beans.ExternalFile">
|
||||
<string>${compiler:sys.install4jHome}/resource/styles/wizard.png</string>
|
||||
</object>
|
||||
</property>
|
||||
<property name="insets">
|
||||
<object class="java.awt.Insets">
|
||||
<int>5</int>
|
||||
<int>10</int>
|
||||
<int>10</int>
|
||||
<int>10</int>
|
||||
</object>
|
||||
</property>
|
||||
</serializedBean>
|
||||
<beans>
|
||||
<formComponent id="43" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" insetTop="0">
|
||||
<serializedBean>
|
||||
<property name="labelFontSizePercent" type="int" value="130" />
|
||||
<property name="labelFontStyle" type="enum" class="com.install4j.runtime.beans.formcomponents.FontStyle" value="BOLD" />
|
||||
<property name="labelFontType" type="enum" class="com.install4j.runtime.beans.formcomponents.FontType" value="DERIVED" />
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
<formComponent id="44" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" />
|
||||
<formComponent id="45" beanClass="com.install4j.runtime.beans.styles.ContentComponent" insetTop="10" insetBottom="0" />
|
||||
</beans>
|
||||
<externalParametrizationPropertyNames>
|
||||
<propertyName>imageAnchor</propertyName>
|
||||
<propertyName>imageEdgeBackgroundColor</propertyName>
|
||||
<propertyName>imageFile</propertyName>
|
||||
</externalParametrizationPropertyNames>
|
||||
</group>
|
||||
<formComponent id="46" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" insetBottom="0">
|
||||
<serializedBean>
|
||||
<property name="styleId" type="string">52</property>
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</formComponents>
|
||||
</style>
|
||||
<group name="Style components" id="47" beanClass="com.install4j.runtime.beans.groups.StyleGroup">
|
||||
<beans>
|
||||
<style name="Standard header" id="48" beanClass="com.install4j.runtime.beans.styles.FormStyle">
|
||||
<serializedBean>
|
||||
<property name="fillVertical" type="boolean" value="false" />
|
||||
<property name="standalone" type="boolean" value="false" />
|
||||
<property name="verticalAnchor" type="enum" class="com.install4j.api.beans.Anchor" value="NORTH" />
|
||||
</serializedBean>
|
||||
<formComponents>
|
||||
<group id="49" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" useExternalParametrization="true" externalParametrizationName="Customize title bar" externalParametrizationMode="include">
|
||||
<serializedBean>
|
||||
<property name="backgroundColor">
|
||||
<object class="java.awt.Color">
|
||||
<int>255</int>
|
||||
<int>255</int>
|
||||
<int>255</int>
|
||||
<int>255</int>
|
||||
</object>
|
||||
</property>
|
||||
<property name="borderSides">
|
||||
<object class="com.install4j.runtime.beans.formcomponents.BorderSides">
|
||||
<property name="bottom" type="boolean" value="true" />
|
||||
</object>
|
||||
</property>
|
||||
<property name="imageAnchor" type="enum" class="com.install4j.api.beans.Anchor" value="NORTHEAST" />
|
||||
<property name="imageEdgeBorderWidth" type="int" value="2" />
|
||||
<property name="imageFile">
|
||||
<object class="com.install4j.api.beans.ExternalFile">
|
||||
<string>icon:${installer:sys.installerApplicationMode}_header.png</string>
|
||||
</object>
|
||||
</property>
|
||||
<property name="imageInsets">
|
||||
<object class="java.awt.Insets">
|
||||
<int>0</int>
|
||||
<int>5</int>
|
||||
<int>1</int>
|
||||
<int>1</int>
|
||||
</object>
|
||||
</property>
|
||||
<property name="insets">
|
||||
<object class="java.awt.Insets">
|
||||
<int>0</int>
|
||||
<int>20</int>
|
||||
<int>0</int>
|
||||
<int>10</int>
|
||||
</object>
|
||||
</property>
|
||||
</serializedBean>
|
||||
<beans>
|
||||
<formComponent name="Title" id="50" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent">
|
||||
<serializedBean>
|
||||
<property name="labelFontStyle" type="enum" class="com.install4j.runtime.beans.formcomponents.FontStyle" value="BOLD" />
|
||||
<property name="labelFontType" type="enum" class="com.install4j.runtime.beans.formcomponents.FontType" value="DERIVED" />
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
<formComponent name="Subtitle" id="51" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" insetLeft="8">
|
||||
<serializedBean>
|
||||
<property name="titleType" type="enum" class="com.install4j.runtime.beans.styles.TitleType" value="SUB_TITLE" />
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</beans>
|
||||
<externalParametrizationPropertyNames>
|
||||
<propertyName>backgroundColor</propertyName>
|
||||
<propertyName>foregroundColor</propertyName>
|
||||
<propertyName>imageAnchor</propertyName>
|
||||
<propertyName>imageFile</propertyName>
|
||||
<propertyName>imageOverlap</propertyName>
|
||||
</externalParametrizationPropertyNames>
|
||||
</group>
|
||||
</formComponents>
|
||||
</style>
|
||||
<style name="Standard footer" id="52" beanClass="com.install4j.runtime.beans.styles.FormStyle">
|
||||
<serializedBean>
|
||||
<property name="fillVertical" type="boolean" value="false" />
|
||||
<property name="standalone" type="boolean" value="false" />
|
||||
<property name="verticalAnchor" type="enum" class="com.install4j.api.beans.Anchor" value="SOUTH" />
|
||||
</serializedBean>
|
||||
<formComponents>
|
||||
<group id="53" beanClass="com.install4j.runtime.beans.groups.HorizontalFormComponentGroup">
|
||||
<serializedBean>
|
||||
<property name="alignFirstLabel" type="boolean" value="false" />
|
||||
<property name="insets">
|
||||
<object class="java.awt.Insets">
|
||||
<int>3</int>
|
||||
<int>5</int>
|
||||
<int>8</int>
|
||||
<int>5</int>
|
||||
</object>
|
||||
</property>
|
||||
</serializedBean>
|
||||
<beans>
|
||||
<formComponent id="54" beanClass="com.install4j.runtime.beans.formcomponents.SpringComponent" />
|
||||
<formComponent name="Back button" id="55" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
|
||||
<serializedBean>
|
||||
<property name="buttonText" type="string">< ${i18n:ButtonBack}</property>
|
||||
<property name="controlButtonType" type="enum" class="com.install4j.api.context.ControlButtonType" value="PREVIOUS" />
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
<formComponent name="Next button" id="56" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
|
||||
<serializedBean>
|
||||
<property name="buttonText" type="string">${i18n:ButtonNext} ></property>
|
||||
<property name="controlButtonType" type="enum" class="com.install4j.api.context.ControlButtonType" value="NEXT" />
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
<formComponent name="Cancel button" id="57" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent" insetLeft="5">
|
||||
<serializedBean>
|
||||
<property name="buttonText" type="string">${i18n:ButtonCancel}</property>
|
||||
<property name="controlButtonType" type="enum" class="com.install4j.api.context.ControlButtonType" value="CANCEL" />
|
||||
</serializedBean>
|
||||
</formComponent>
|
||||
</beans>
|
||||
</group>
|
||||
</formComponents>
|
||||
</style>
|
||||
</beans>
|
||||
</group>
|
||||
</styles>
|
||||
</installerGui>
|
||||
<mediaSets>
|
||||
<windows name="Windows" id="59">
|
||||
<jreBundle jdkProviderId="AdoptOpenJDK" release="openjdk15/jdk-15+36" usePack200="false" overrideJdkRelease="true" jreBundleSource="generated" shared="true">
|
||||
<modules>
|
||||
<defaultModules set="jre" />
|
||||
<jmodDirectory location="/home/ubuntu/.local/lib/jvm/windows-javafx-jmods-15/" />
|
||||
</modules>
|
||||
</jreBundle>
|
||||
</windows>
|
||||
<linuxDeb name="Linux Deb Archive" id="61" require64BitVm="true">
|
||||
<jreBundle jdkProviderId="AdoptOpenJDK" release="openjdk15/jdk-15+36" overrideJdkRelease="true" jreBundleSource="generated" manualJreEntry="true">
|
||||
<modules>
|
||||
<defaultModules set="jre" />
|
||||
<jmodDirectory location="/home/ubuntu/.local/lib/jvm/linux-javafx-jmods-15/" />
|
||||
</modules>
|
||||
</jreBundle>
|
||||
</linuxDeb>
|
||||
</mediaSets>
|
||||
<buildIds>
|
||||
<mediaSet refId="61" />
|
||||
</buildIds>
|
||||
</install4j>
|
86
pom.xml
86
pom.xml
@ -7,8 +7,6 @@
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>15</maven.compiler.source>
|
||||
<maven.compiler.target>15</maven.compiler.target>
|
||||
</properties>
|
||||
<repositories>
|
||||
<repository>
|
||||
@ -33,22 +31,65 @@
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>15</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>15</version>
|
||||
<classifier>win</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>15</version>
|
||||
<classifier>linux</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>15</version>
|
||||
<classifier>mac</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlib-session-container</artifactId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-base</artifactId>
|
||||
<version>15</version>
|
||||
<classifier>linux</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-base</artifactId>
|
||||
<version>15</version>
|
||||
<classifier>win</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-base</artifactId>
|
||||
<version>15</version>
|
||||
<classifier>mac</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.libphonenumber</groupId>
|
||||
<artifactId>libphonenumber</artifactId>
|
||||
<version>8.12.11</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<release>15</release>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-maven-plugin</artifactId>
|
||||
@ -65,22 +106,39 @@
|
||||
<mainClass>it.cavallium/it.cavallium.App</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-all</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer implementation=
|
||||
"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>it.cavallium.Launcher</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
41
src/main/java/it/cavallium/AddUserBotResult.java
Normal file
41
src/main/java/it/cavallium/AddUserBotResult.java
Normal file
@ -0,0 +1,41 @@
|
||||
package it.cavallium;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
import reactor.util.annotation.Nullable;
|
||||
|
||||
public class AddUserBotResult {
|
||||
|
||||
private final String errorMessage;
|
||||
|
||||
private AddUserBotResult(@Nullable String errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public static AddUserBotResult newSuccess() {
|
||||
return new AddUserBotResult(null);
|
||||
}
|
||||
|
||||
public static AddUserBotResult newFailed(String errorMessage) {
|
||||
return new AddUserBotResult(Objects.requireNonNull(errorMessage));
|
||||
}
|
||||
|
||||
public boolean success() {
|
||||
return errorMessage == null;
|
||||
}
|
||||
|
||||
public boolean failed() {
|
||||
return errorMessage != null;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringJoiner(", ", AddUserBotResult.class.getSimpleName() + "[", "]")
|
||||
.add("errorMessage='" + errorMessage + "'")
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -1,5 +1,10 @@
|
||||
package it.cavallium;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import it.tdlight.common.Init;
|
||||
import it.tdlight.common.utils.CantLoadLibrary;
|
||||
import it.tdlight.tdlibsession.td.middle.TdClusterManager;
|
||||
import java.time.Duration;
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
@ -13,15 +18,33 @@ import java.io.IOException;
|
||||
*/
|
||||
public class App extends Application {
|
||||
|
||||
public static final String VERSION = "1.0.0";
|
||||
private static TdClusterManager clusterManager;
|
||||
|
||||
private static TransferService transferService;
|
||||
|
||||
private static Scene scene;
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws IOException {
|
||||
scene = new Scene(loadFXML("primary"), 640, 480);
|
||||
public void start(Stage stage) throws IOException, CantLoadLibrary {
|
||||
Init.start();
|
||||
clusterManager = new TdClusterManager(null, null, Vertx.vertx(), null);
|
||||
transferService = new TransferServiceImpl(clusterManager);
|
||||
|
||||
transferService.setApiId(94575);
|
||||
transferService.setApiHash("a3406de8d171bb422bb6ddf3bbd800e2");
|
||||
|
||||
scene = new Scene(loadFXML("primary"), 800, 600);
|
||||
stage.setScene(scene);
|
||||
stage.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
App.getTransferService().quit().block(Duration.ofSeconds(15));
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
static void setRoot(String fxml) throws IOException {
|
||||
scene.setRoot(loadFXML(fxml));
|
||||
}
|
||||
@ -35,4 +58,7 @@ public class App extends Application {
|
||||
launch();
|
||||
}
|
||||
|
||||
public static TransferService getTransferService() {
|
||||
return transferService;
|
||||
}
|
||||
}
|
45
src/main/java/it/cavallium/BaseChatInfo.java
Normal file
45
src/main/java/it/cavallium/BaseChatInfo.java
Normal file
@ -0,0 +1,45 @@
|
||||
package it.cavallium;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class BaseChatInfo {
|
||||
private final long supergroupId;
|
||||
private final String title;
|
||||
|
||||
public BaseChatInfo(long supergroupId, String title) {
|
||||
this.supergroupId = supergroupId;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public long getSupergroupId() {
|
||||
return supergroupId;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseChatInfo that = (BaseChatInfo) o;
|
||||
|
||||
return supergroupId == that.supergroupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) (supergroupId ^ (supergroupId >>> 32));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (supergroupId + " " + title).trim();
|
||||
}
|
||||
}
|
7
src/main/java/it/cavallium/Launcher.java
Normal file
7
src/main/java/it/cavallium/Launcher.java
Normal file
@ -0,0 +1,7 @@
|
||||
package it.cavallium;
|
||||
|
||||
public class Launcher {
|
||||
public static void main(String[] args) {
|
||||
App.main(args);
|
||||
}
|
||||
}
|
49
src/main/java/it/cavallium/MonoFxUtils.java
Normal file
49
src/main/java/it/cavallium/MonoFxUtils.java
Normal file
@ -0,0 +1,49 @@
|
||||
package it.cavallium;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Dialog;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class MonoFxUtils {
|
||||
public static <T> Mono<T> showAndWait(Dialog<T> dialog) {
|
||||
return Mono.create(sink -> {
|
||||
Platform.runLater(() -> {
|
||||
dialog.setOnHidden(event -> {
|
||||
if (dialog.getResult() != null) {
|
||||
sink.success(dialog.getResult());
|
||||
} else {
|
||||
sink.success();
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> Mono<Optional<T>> showAndWaitOpt(Dialog<T> dialog) {
|
||||
return Mono.create(sink -> {
|
||||
Platform.runLater(() -> {
|
||||
dialog.setOnHidden(event -> {
|
||||
sink.success(Optional.<T>ofNullable(dialog.getResult()));
|
||||
});
|
||||
dialog.show();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> Mono<T> runLater(Supplier<Mono<T>> mono) {
|
||||
return Mono.create(sink -> {
|
||||
Platform.runLater(() -> {
|
||||
mono.get().subscribe(value -> {
|
||||
sink.success(value);
|
||||
}, e -> {
|
||||
sink.error(e);
|
||||
}, () -> {
|
||||
sink.success();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -1,12 +1,262 @@
|
||||
package it.cavallium;
|
||||
|
||||
import com.google.i18n.phonenumbers.NumberParseException;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
|
||||
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.Event;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Alert.AlertType;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.TextInputDialog;
|
||||
import javafx.scene.input.InputMethodEvent;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.text.Text;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
public class PrimaryController {
|
||||
|
||||
@FXML private Pane main;
|
||||
@FXML private TextField phoneNumber;
|
||||
@FXML private ListView<Text> userbotsList;
|
||||
@FXML private ComboBox<BaseChatInfo> sourceGroupCombo;
|
||||
@FXML private ComboBox<BaseChatInfo> destGroupCombo;
|
||||
|
||||
@FXML
|
||||
private void switchToSecondary() throws IOException {
|
||||
App.setRoot("secondary");
|
||||
protected void initialize() {
|
||||
for (PhoneNumber number : App.getTransferService().getPhoneNumbers()) {
|
||||
userbotsList
|
||||
.getItems()
|
||||
.add(0,
|
||||
new Text(getUserbotPrettyPrintPhoneNumber(number))
|
||||
);
|
||||
}
|
||||
|
||||
var srcItems = sourceGroupCombo.getItems();
|
||||
srcItems.clear();
|
||||
for (BaseChatInfo originSupergroups : App.getTransferService().getAdminSupergroups(true, false)) {
|
||||
srcItems.add(originSupergroups);
|
||||
}
|
||||
|
||||
var destItems = destGroupCombo.getItems();
|
||||
destItems.clear();
|
||||
for (BaseChatInfo destSupergroups : App.getTransferService().getAdminSupergroups(false, true)) {
|
||||
destItems.add(destSupergroups);
|
||||
}
|
||||
}
|
||||
|
||||
private void disableClicks() {
|
||||
main.setDisable(true);
|
||||
}
|
||||
|
||||
private void enableClicks() {
|
||||
main.setDisable(false);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void openSettings(ActionEvent actionEvent) throws IOException {
|
||||
App.setRoot("settings");
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void quit(ActionEvent actionEvent) {
|
||||
Platform.exit();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void addUserbot(ActionEvent actionEvent) {
|
||||
var eventSource = (Node) actionEvent.getSource();
|
||||
var phoneNumberText = phoneNumber.getText();
|
||||
try {
|
||||
var phoneNumber = getUserbotPhoneNumber(phoneNumberText);
|
||||
var phoneNumberPrettyText = getUserbotPrettyPrintPhoneNumber(phoneNumber);
|
||||
|
||||
disableClicks();
|
||||
App.getTransferService().addUserbot(phoneNumber, (client) -> MonoFxUtils.runLater(() -> {
|
||||
var authCodeAlert = new TextInputDialog();
|
||||
authCodeAlert.setHeaderText("Insert authentication code that you received");
|
||||
return PrimaryController.<Integer>loopAlert(authCodeAlert, (authCodeText) -> {
|
||||
if (authCodeText.matches("^[0-9]{3,8}$")) {
|
||||
try {
|
||||
int authCode = Integer.parseUnsignedInt(authCodeText);
|
||||
return Mono.just(authCode);
|
||||
} catch (NumberFormatException ex) {
|
||||
var alert = new Alert(AlertType.ERROR, "Can't parse authentication code number", ButtonType.CLOSE);
|
||||
return MonoFxUtils.showAndWait(alert).then(Mono.empty());
|
||||
}
|
||||
} else {
|
||||
var alert = new Alert(AlertType.ERROR, "Wrong authentication code number format", ButtonType.CLOSE);
|
||||
return MonoFxUtils.showAndWait(alert).then(Mono.empty());
|
||||
}
|
||||
});
|
||||
}), (client, hint) -> MonoFxUtils.runLater(() -> {
|
||||
String hintText = "";
|
||||
if (hint != null && !hint.isBlank()) {
|
||||
hintText = " (hint: " + hint + ")";
|
||||
}
|
||||
var otpAlert = new TextInputDialog();
|
||||
otpAlert.setHeaderText("Insert user password" + hintText + ":");
|
||||
return loopAlert(otpAlert, (otpText) -> {
|
||||
if (otpText.length() > 0) {
|
||||
return Mono.just(otpText);
|
||||
} else {
|
||||
var alert = new Alert(AlertType.ERROR, "Wrong user password format", ButtonType.CLOSE);
|
||||
alert.showAndWait();
|
||||
return Mono.empty();
|
||||
}
|
||||
});
|
||||
}), () -> {
|
||||
// closed, remove from list
|
||||
return MonoFxUtils.runLater(() -> {
|
||||
userbotsList.getItems().removeIf(textBox -> {
|
||||
try {
|
||||
return getUserbotPhoneNumber(textBox.getText()).equals(phoneNumber);
|
||||
} catch (NumberParseException e) {
|
||||
// Can't happen
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return Mono.empty();
|
||||
});
|
||||
}).handle((result, sink) -> {
|
||||
if (result.failed()) {
|
||||
sink.error(new Exception(result.getErrorMessage()));
|
||||
} else {
|
||||
sink.next(result);
|
||||
}
|
||||
}).flatMap((_v) -> MonoFxUtils.runLater(() -> {
|
||||
var alert = new Alert(AlertType.INFORMATION,
|
||||
"Added userbot " + PhoneNumberUtil
|
||||
.getInstance()
|
||||
.format(phoneNumber, PhoneNumberFormat.INTERNATIONAL),
|
||||
ButtonType.CLOSE
|
||||
);
|
||||
return MonoFxUtils.showAndWait(alert);
|
||||
})).doOnSuccess((_v) -> {
|
||||
userbotsList
|
||||
.getItems()
|
||||
.add(0,
|
||||
new Text(phoneNumberPrettyText)
|
||||
);
|
||||
this.phoneNumber.setText("");
|
||||
})
|
||||
.doOnTerminate(this::enableClicks)
|
||||
.subscribe(_v -> {}, error -> {
|
||||
Platform.runLater(() -> {
|
||||
var alert = new Alert(AlertType.ERROR,
|
||||
"Error while adding the userbot " + PhoneNumberUtil
|
||||
.getInstance()
|
||||
.format(phoneNumber, PhoneNumberFormat.INTERNATIONAL),
|
||||
ButtonType.CLOSE
|
||||
);
|
||||
alert.setContentText(error.getLocalizedMessage());
|
||||
MonoFxUtils.showAndWait(alert).subscribe();
|
||||
|
||||
enableClicks();
|
||||
});
|
||||
});
|
||||
} catch (NumberFormatException | NumberParseException ex) {
|
||||
var alert = new Alert(AlertType.ERROR, "Can't parse phone number format", ButtonType.CLOSE);
|
||||
alert.showAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
private String getUserbotPrettyPrintPhoneNumber(PhoneNumber phoneNumber) {
|
||||
return PhoneNumberUtil
|
||||
.getInstance()
|
||||
.format(phoneNumber, PhoneNumberFormat.INTERNATIONAL);
|
||||
}
|
||||
|
||||
public static PhoneNumber getUserbotPhoneNumber(String phoneNumberText) throws NumberParseException {
|
||||
return PhoneNumberUtil
|
||||
.getInstance()
|
||||
.parse(phoneNumberText, PhoneNumberUtil.getCountryMobileToken(1));
|
||||
}
|
||||
|
||||
private static <T> Mono<T> loopAlert(TextInputDialog alert, Function<String, Mono<T>> resultParser) {
|
||||
return MonoFxUtils.showAndWaitOpt(alert)
|
||||
.flatMap(resultOpt -> {
|
||||
if (resultOpt.isEmpty()) {
|
||||
return Mono.just(Optional.<T>empty());
|
||||
} else {
|
||||
return resultParser.apply(resultOpt.get()).filter(Objects::nonNull).map(Optional::of);
|
||||
}
|
||||
})
|
||||
.repeatWhen(s -> s.takeWhile(n -> n == 0))
|
||||
.last(Optional.empty())
|
||||
.flatMap(opt -> opt.map(Mono::just).orElseGet(Mono::empty));
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void removeUserbot(ActionEvent actionEvent) {
|
||||
var selectedItem = userbotsList.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem != null) {
|
||||
disableClicks();
|
||||
try {
|
||||
var phoneNumber = getUserbotPhoneNumber(selectedItem.getText());
|
||||
|
||||
App.getTransferService()
|
||||
.closeUserbot(phoneNumber)
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.then(MonoFxUtils.runLater(() -> {
|
||||
// closed, remove from list
|
||||
userbotsList.getItems().remove(selectedItem);
|
||||
return Mono.empty();
|
||||
}))
|
||||
.doOnTerminate(this::enableClicks)
|
||||
.subscribe();
|
||||
} catch (NumberParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onSourceGroupAction(ActionEvent actionEvent) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onSourceGroupHiding(Event event) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onSourceGroupTextChanged(InputMethodEvent inputMethodEvent) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onSourceGroupShowing(Event event) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onDestGroupAction(ActionEvent actionEvent) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onDestGroupHiding(Event event) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onDestGroupTextChanged(InputMethodEvent inputMethodEvent) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onDestGroupShowing(Event event) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onDoTransfer(ActionEvent actionEvent) {
|
||||
}
|
||||
}
|
||||
|
7
src/main/java/it/cavallium/TChatType.java
Normal file
7
src/main/java/it/cavallium/TChatType.java
Normal file
@ -0,0 +1,7 @@
|
||||
package it.cavallium;
|
||||
|
||||
public enum TChatType {
|
||||
SUPERGROUP,
|
||||
USER,
|
||||
BASICGROUP
|
||||
}
|
112
src/main/java/it/cavallium/TransferClient.java
Normal file
112
src/main/java/it/cavallium/TransferClient.java
Normal file
@ -0,0 +1,112 @@
|
||||
package it.cavallium;
|
||||
|
||||
import it.tdlight.jni.TdApi;
|
||||
import it.tdlight.jni.TdApi.Chat;
|
||||
import it.tdlight.jni.TdApi.ChatMemberStatusAdministrator;
|
||||
import it.tdlight.jni.TdApi.GetSupergroupFullInfo;
|
||||
import it.tdlight.jni.TdApi.Object;
|
||||
import it.tdlight.jni.TdApi.Supergroup;
|
||||
import it.tdlight.jni.TdApi.SupergroupFullInfo;
|
||||
import it.tdlight.jni.TdApi.Update;
|
||||
import it.tdlight.jni.TdApi.UpdateNewChat;
|
||||
import it.tdlight.jni.TdApi.UpdateSupergroup;
|
||||
import it.tdlight.jni.TdApi.UpdateSupergroupFullInfo;
|
||||
import it.tdlight.tdlibsession.td.TdResult;
|
||||
import it.tdlight.tdlibsession.td.easy.AsyncTdEasy;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
public class TransferClient {
|
||||
|
||||
private final AsyncTdEasy client;
|
||||
private final ConcurrentHashMap<Integer, Supergroup> supergroupInfos = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<Integer, SupergroupFullInfo> supergroupFullInfos = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<Long, Chat> chats = new ConcurrentHashMap<>();
|
||||
|
||||
public TransferClient(AsyncTdEasy client) {
|
||||
this.client = client;
|
||||
|
||||
this.client.getIncomingUpdates()
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.flatMap(this::onUpdate)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private Mono<Void> onUpdate(Update update) {
|
||||
switch (update.getConstructor()) {
|
||||
case UpdateSupergroup.CONSTRUCTOR:
|
||||
return this.onUpdateSupergroup(((UpdateSupergroup) update).supergroup);
|
||||
case UpdateSupergroupFullInfo.CONSTRUCTOR:
|
||||
return this.onUpdateSupergroupFullInfo(
|
||||
((UpdateSupergroupFullInfo) update).supergroupId,
|
||||
((UpdateSupergroupFullInfo) update).supergroupFullInfo);
|
||||
case UpdateNewChat.CONSTRUCTOR:
|
||||
return this.onChat(((UpdateNewChat) update).chat);
|
||||
default:
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<Void> onChat(Chat chat) {
|
||||
if (chats.put(chat.id, chat) == null) {
|
||||
// ok
|
||||
}
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
private Mono<Void> onUpdateSupergroup(Supergroup supergroup) {
|
||||
if (supergroupInfos.put(supergroup.id, supergroup) == null) {
|
||||
return this
|
||||
.<SupergroupFullInfo>send(new GetSupergroupFullInfo(supergroup.id))
|
||||
.filter(TdResult::succeeded)
|
||||
.map(TdResult::result)
|
||||
.flatMap(supergroupFullInfo -> onUpdateSupergroupFullInfo(supergroup.id, supergroupFullInfo));
|
||||
}
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
private Mono<Void> onUpdateSupergroupFullInfo(int id, SupergroupFullInfo supergroupFullInfo) {
|
||||
if (supergroupFullInfos.put(id, supergroupFullInfo) == null) {
|
||||
// ok
|
||||
}
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to TDLib.
|
||||
* @return The response or {@link TdApi.Error}.
|
||||
*/
|
||||
public <T extends Object> Mono<TdResult<T>> send(TdApi.Function request) {
|
||||
return client.send(request);
|
||||
}
|
||||
|
||||
public Set<BaseChatInfo> getAdminSupergroups(boolean canRestrictMembers, boolean canInviteUsers) {
|
||||
return supergroupFullInfos.entrySet().stream().flatMap(entry -> {
|
||||
int id = entry.getKey();
|
||||
var fullInfo = entry.getValue();
|
||||
var chatInfo = chats.get(TransferUtils.chatEntityIdToChatId(id, TChatType.SUPERGROUP));
|
||||
var baseInfo = supergroupInfos.get(id);
|
||||
if (chatInfo == null || baseInfo == null) {
|
||||
return Stream.<BaseChatInfo>empty();
|
||||
} else {
|
||||
if (baseInfo.status.getConstructor() != ChatMemberStatusAdministrator.CONSTRUCTOR) {
|
||||
return Stream.empty();
|
||||
}
|
||||
var adminStatus = (ChatMemberStatusAdministrator) baseInfo.status;
|
||||
if (!adminStatus.canRestrictMembers && canRestrictMembers) {
|
||||
return Stream.empty();
|
||||
}
|
||||
if (!adminStatus.canInviteUsers && canInviteUsers) {
|
||||
return Stream.empty();
|
||||
}
|
||||
var baseChatInfo = new BaseChatInfo(id, chatInfo.title);
|
||||
return Stream.<BaseChatInfo>of(baseChatInfo);
|
||||
}
|
||||
}).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
29
src/main/java/it/cavallium/TransferService.java
Normal file
29
src/main/java/it/cavallium/TransferService.java
Normal file
@ -0,0 +1,29 @@
|
||||
package it.cavallium;
|
||||
|
||||
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
||||
import it.tdlight.tdlibsession.td.easy.AsyncTdEasy;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface TransferService {
|
||||
|
||||
void setApiId(int apiId);
|
||||
|
||||
void setApiHash(String apiHash);
|
||||
|
||||
Mono<AddUserBotResult> addUserbot(PhoneNumber phoneNumber,
|
||||
Function<AsyncTdEasy, Mono<Integer>> codeSupplier,
|
||||
BiFunction<AsyncTdEasy, String, Mono<String>> otpSupplier,
|
||||
Supplier<Mono<Void>> onUserbotClosed);
|
||||
|
||||
Mono<Void> quit();
|
||||
|
||||
Mono<Void> closeUserbot(PhoneNumber phoneNumber);
|
||||
|
||||
Set<PhoneNumber> getPhoneNumbers();
|
||||
|
||||
Set<BaseChatInfo> getAdminSupergroups(boolean canRestrictMembers, boolean canInviteUsers);
|
||||
}
|
226
src/main/java/it/cavallium/TransferServiceImpl.java
Normal file
226
src/main/java/it/cavallium/TransferServiceImpl.java
Normal file
@ -0,0 +1,226 @@
|
||||
package it.cavallium;
|
||||
|
||||
import static it.cavallium.PrimaryController.getUserbotPhoneNumber;
|
||||
|
||||
import com.google.i18n.phonenumbers.NumberParseException;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
|
||||
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
||||
import it.tdlight.jni.TdApi;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateClosed;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateClosing;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateLoggingOut;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateReady;
|
||||
import it.tdlight.jni.TdApi.Update;
|
||||
import it.tdlight.jni.TdApi.UpdateSupergroup;
|
||||
import it.tdlight.tdlibsession.td.easy.AsyncTdEasy;
|
||||
import it.tdlight.tdlibsession.td.easy.ParameterInfoPasswordHint;
|
||||
import it.tdlight.tdlibsession.td.easy.TdEasySettings;
|
||||
import it.tdlight.tdlibsession.td.middle.TdClusterManager;
|
||||
import it.tdlight.tdlibsession.td.middle.direct.AsyncTdMiddleDirect;
|
||||
import it.tdlight.utils.MonoUtils;
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.warp.commonutils.error.InitializationException;
|
||||
import reactor.core.publisher.EmitterProcessor;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
public class TransferServiceImpl implements TransferService {
|
||||
|
||||
private final TdClusterManager clusterManager;
|
||||
private final ConcurrentHashMap<Long, TransferClient> clients = new ConcurrentHashMap<>();
|
||||
private int apiId;
|
||||
private String apiHash;
|
||||
|
||||
public TransferServiceImpl(TdClusterManager clusterManager) {
|
||||
this.clusterManager = clusterManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApiId(int apiId) {
|
||||
this.apiId = apiId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApiHash(String apiHash) {
|
||||
this.apiHash = apiHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AddUserBotResult> addUserbot(PhoneNumber phoneNumber,
|
||||
Function<AsyncTdEasy, Mono<Integer>> codeSupplier,
|
||||
BiFunction<AsyncTdEasy, String, Mono<String>> otpSupplier,
|
||||
Supplier<Mono<Void>> onUserbotClosed) {
|
||||
|
||||
long phoneNumberLong = getLongPhoneNumber(phoneNumber);
|
||||
|
||||
if (clients.containsKey(phoneNumberLong)) {
|
||||
return Mono.just(AddUserBotResult.newFailed("Userbot already added!"));
|
||||
}
|
||||
|
||||
String alias = PhoneNumberUtil.getInstance().format(phoneNumber, PhoneNumberFormat.INTERNATIONAL);
|
||||
return Mono
|
||||
.fromCallable(() -> {
|
||||
return AsyncTdMiddleDirect.getAndDeployInstance(clusterManager, alias, "" + phoneNumberLong);
|
||||
})
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.flatMap(v -> v)
|
||||
.map(middle -> new AsyncTdEasy(middle, alias))
|
||||
.flatMap(client -> {
|
||||
return client
|
||||
.create(TdEasySettings
|
||||
.newBuilder()
|
||||
.setUseMessageDatabase(false)
|
||||
.setUseFileDatabase(false)
|
||||
.setUseChatInfoDatabase(false)
|
||||
.setApiId(apiId)
|
||||
.setApiHash(apiHash)
|
||||
.setEnableStorageOptimizer(false)
|
||||
.setApplicationVersion(App.VERSION)
|
||||
.setDatabaseDirectory("sessions" + File.separator + "userbot_" + phoneNumberLong)
|
||||
.setIgnoreFileNames(true)
|
||||
.setPhoneNumber(phoneNumberLong)
|
||||
.setSystemLanguageCode("en")
|
||||
.setDeviceModel(System.getProperty("os.name"))
|
||||
.setSystemVersion(System.getProperty("os.version"))
|
||||
.setParameterRequestHandler((parameter, parameterInfo) -> {
|
||||
switch (parameter) {
|
||||
case ASK_FIRST_NAME:
|
||||
return Mono.just("FirstName");
|
||||
case ASK_LAST_NAME:
|
||||
return Mono.just("LastName");
|
||||
case ASK_CODE:
|
||||
return codeSupplier
|
||||
.apply(client)
|
||||
.map(i -> "" + i)
|
||||
.switchIfEmpty(client
|
||||
.send(new TdApi.Close())
|
||||
.materialize()
|
||||
.flatMap(signal -> onUserbotClosed.get().thenReturn(signal))
|
||||
.dematerialize()
|
||||
.then(Mono.empty()));
|
||||
case ASK_PASSWORD:
|
||||
return otpSupplier
|
||||
.apply(client, ((ParameterInfoPasswordHint) parameterInfo).getHint())
|
||||
.switchIfEmpty(client
|
||||
.send(new TdApi.Close())
|
||||
.materialize()
|
||||
.flatMap(signal -> onUserbotClosed.get().thenReturn(signal))
|
||||
.dematerialize()
|
||||
.then(Mono.empty()));
|
||||
case NOTIFY_LINK:
|
||||
default:
|
||||
return Mono.empty();
|
||||
}
|
||||
})
|
||||
.build())
|
||||
.then(Mono.defer(() -> {
|
||||
var clientStateFlux = client.getState().skip(1).publish().autoConnect(2);
|
||||
|
||||
clientStateFlux
|
||||
.filter(state -> state.getConstructor() == AuthorizationStateClosing.CONSTRUCTOR
|
||||
|| state.getConstructor() == AuthorizationStateClosed.CONSTRUCTOR
|
||||
|| state.getConstructor() == AuthorizationStateLoggingOut.CONSTRUCTOR)
|
||||
.take(1)
|
||||
.singleOrEmpty()
|
||||
.then()
|
||||
.materialize()
|
||||
.flatMap(signal -> onUserbotClosed.get().thenReturn(signal))
|
||||
.dematerialize()
|
||||
.subscribe(state -> System.out.println("State: " + state));
|
||||
|
||||
client.getIncomingUpdates()
|
||||
.flatMap(this::onClientUpdate)
|
||||
.subscribe(u -> System.out.println(u), e-> System.err.println(e));
|
||||
|
||||
return clientStateFlux
|
||||
.filter(state -> state.getConstructor() == AuthorizationStateClosing.CONSTRUCTOR
|
||||
|| state.getConstructor() == AuthorizationStateClosed.CONSTRUCTOR
|
||||
|| state.getConstructor() == AuthorizationStateLoggingOut.CONSTRUCTOR
|
||||
|| state.getConstructor() == AuthorizationStateReady.CONSTRUCTOR)
|
||||
.take(1)
|
||||
.singleOrEmpty()
|
||||
.doOnNext(state -> System.out.println("aState: " + state))
|
||||
.handle((state, sink) -> {
|
||||
if (state.getConstructor() == AuthorizationStateReady.CONSTRUCTOR) {
|
||||
sink.complete();
|
||||
} else {
|
||||
sink.error(new Exception(state.getClass().getSimpleName()));
|
||||
}
|
||||
})
|
||||
.then();
|
||||
}))
|
||||
.doOnSuccess((_v) -> clients.put(phoneNumberLong, new TransferClient(client)));
|
||||
|
||||
})
|
||||
.map(_v -> AddUserBotResult.newSuccess());
|
||||
}
|
||||
|
||||
private Mono<Void> onClientUpdate(Update update) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
private static long getLongPhoneNumber(PhoneNumber phoneNumber) {
|
||||
return Long.parseLong(PhoneNumberUtil
|
||||
.getInstance()
|
||||
.format(phoneNumber, PhoneNumberFormat.E164)
|
||||
.replace("+", ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> closeUserbot(PhoneNumber phoneNumber) {
|
||||
var client = clients.remove(getLongPhoneNumber(phoneNumber));
|
||||
if (client == null) {
|
||||
return Mono.error(new Exception("Userbot " + phoneNumber + " was not found!"));
|
||||
} else {
|
||||
return MonoUtils.thenOrError(client.send(new TdApi.Close()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PhoneNumber> getPhoneNumbers() {
|
||||
var phonenumbers = new HashSet<PhoneNumber>();
|
||||
clients.forEach((phoneNumberLong, client) -> {
|
||||
try {
|
||||
phonenumbers.add(getUserbotPhoneNumber("+" + phoneNumberLong));
|
||||
} catch (NumberParseException e) {
|
||||
// Can't happen
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
return phonenumbers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<BaseChatInfo> getAdminSupergroups(boolean canRestrictMembers, boolean canInviteUsers) {
|
||||
var adminSupergroups = clients
|
||||
.values()
|
||||
.stream()
|
||||
.flatMap((TransferClient transferClient) -> transferClient
|
||||
.getAdminSupergroups(canRestrictMembers, canInviteUsers)
|
||||
.stream())
|
||||
.collect(Collectors.toSet());
|
||||
return adminSupergroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> quit() {
|
||||
return Flux
|
||||
.fromIterable(clients.values())
|
||||
.flatMap(client -> client.send(new TdApi.Close()))
|
||||
.log()
|
||||
.collectList()
|
||||
.then();
|
||||
}
|
||||
}
|
28
src/main/java/it/cavallium/TransferUtils.java
Normal file
28
src/main/java/it/cavallium/TransferUtils.java
Normal file
@ -0,0 +1,28 @@
|
||||
package it.cavallium;
|
||||
|
||||
public class TransferUtils {
|
||||
|
||||
public static int chatIdToChatEntityId(long id) {
|
||||
if (id <= -1000000000000L) {
|
||||
return (int) (Math.abs(id) - 1000000000000L);
|
||||
}
|
||||
if (id < 0) {
|
||||
return (int) Math.abs(id);
|
||||
} else {
|
||||
return (int) Math.abs(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static long chatEntityIdToChatId(int chatEntityId, TChatType chatType) {
|
||||
switch (chatType) {
|
||||
case BASICGROUP:
|
||||
return -Math.abs(chatEntityId);
|
||||
case SUPERGROUP:
|
||||
return -1000000000000L - (long) Math.abs(chatEntityId);
|
||||
case USER:
|
||||
return Math.abs(chatEntityId);
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported chat id type: " + chatEntityId);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
module it.cavallium {
|
||||
requires javafx.controls;
|
||||
requires javafx.fxml;
|
||||
|
||||
opens it.cavallium to javafx.fxml;
|
||||
exports it.cavallium;
|
||||
}
|
3
src/main/resources/META-INF/MANIFEST.MF
Normal file
3
src/main/resources/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: it.cavallium.Launcher
|
||||
|
@ -1,16 +1,153 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ComboBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ListView?>
|
||||
<?import javafx.scene.control.Menu?>
|
||||
<?import javafx.scene.control.MenuBar?>
|
||||
<?import javafx.scene.control.MenuItem?>
|
||||
<?import javafx.scene.control.ProgressBar?>
|
||||
<?import javafx.scene.control.SeparatorMenuItem?>
|
||||
<?import javafx.scene.control.SplitPane?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.control.ToolBar?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.paint.Color?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
|
||||
<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="it.cavallium.PrimaryController">
|
||||
<children>
|
||||
<Label text="Primary View" />
|
||||
<Button fx:id="primaryButton" text="Switch to Secondary View" onAction="#switchToSecondary"/>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
|
||||
</padding>
|
||||
<VBox fx:id="main" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="it.cavallium.PrimaryController">
|
||||
<children>
|
||||
<MenuBar VBox.vgrow="NEVER">
|
||||
<menus>
|
||||
<Menu mnemonicParsing="false" text="File">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" onAction="#openSettings" text="Preferences…" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#quit" text="Quit" />
|
||||
</items>
|
||||
</Menu>
|
||||
</menus>
|
||||
</MenuBar>
|
||||
<SplitPane dividerPositions="0.8237442922374429" orientation="VERTICAL">
|
||||
<items>
|
||||
<SplitPane dividerPositions="0.5" focusTraversable="true" prefHeight="-1.0" prefWidth="-1.0">
|
||||
<items>
|
||||
<BorderPane>
|
||||
<top>
|
||||
<Label alignment="CENTER" prefWidth="-1.0" style=" " text="Userbots" textAlignment="CENTER" wrapText="false" BorderPane.alignment="CENTER">
|
||||
<font>
|
||||
<Font size="18.0" fx:id="x1" />
|
||||
</font>
|
||||
<textFill>
|
||||
<Color blue="0.624" green="0.624" red="0.624" fx:id="x2" />
|
||||
</textFill>
|
||||
</Label>
|
||||
</top>
|
||||
<center>
|
||||
<ListView fx:id="userbotsList" BorderPane.alignment="CENTER" />
|
||||
</center>
|
||||
<bottom>
|
||||
<ToolBar prefHeight="40.0" BorderPane.alignment="CENTER">
|
||||
<items>
|
||||
<TextField fx:id="phoneNumber" onAction="#addUserbot" prefHeight="25.0" promptText="Phone number">
|
||||
<font>
|
||||
<Font size="9.0" />
|
||||
</font>
|
||||
</TextField>
|
||||
<Button mnemonicParsing="false" onAction="#addUserbot" prefHeight="25.0" text="Add" />
|
||||
<Button fx:id="removeUserbotBtn" mnemonicParsing="false" onAction="#removeUserbot" prefHeight="25.0" text="Remove" />
|
||||
</items>
|
||||
</ToolBar>
|
||||
</bottom>
|
||||
</BorderPane>
|
||||
<BorderPane>
|
||||
<top>
|
||||
<Label alignment="CENTER" prefWidth="-1.0" style=" " text="Transfer" textAlignment="CENTER" wrapText="false" BorderPane.alignment="CENTER">
|
||||
<font>
|
||||
<Font size="18.0" fx:id="x11" />
|
||||
</font>
|
||||
<textFill>
|
||||
<Color blue="0.624" green="0.624" red="0.624" fx:id="x21" />
|
||||
</textFill>
|
||||
</Label>
|
||||
</top>
|
||||
<center>
|
||||
<GridPane BorderPane.alignment="CENTER">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints />
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
<RowConstraints vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<VBox maxHeight="-Infinity" minHeight="-Infinity" spacing="10.0" GridPane.columnSpan="2">
|
||||
<children>
|
||||
<ComboBox fx:id="sourceGroupCombo" editable="true" onAction="#onSourceGroupAction" onHiding="#onSourceGroupHiding" onInputMethodTextChanged="#onSourceGroupTextChanged" onShowing="#onSourceGroupShowing" prefHeight="28.0" promptText="Source group" visibleRowCount="40" />
|
||||
<ComboBox fx:id="destGroupCombo" editable="true" onAction="#onDestGroupAction" onHiding="#onDestGroupHiding" onInputMethodTextChanged="#onDestGroupTextChanged" onShowing="#onDestGroupShowing" prefHeight="28.0" promptText="Destination group" visibleRowCount="40" VBox.vgrow="ALWAYS" />
|
||||
<Button fx:id="transferBtn" mnemonicParsing="false" onAction="#onDoTransfer" text="Transfer" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
<TableView fx:id="statusTable" GridPane.columnSpan="2" GridPane.rowIndex="1">
|
||||
<columns>
|
||||
<TableColumn minWidth="100.0" prefWidth="200.0" text="User" />
|
||||
<TableColumn minWidth="100.0" prefWidth="100.0" text="Status" />
|
||||
</columns>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||
</columnResizePolicy>
|
||||
</TableView>
|
||||
</children>
|
||||
</GridPane>
|
||||
</center>
|
||||
</BorderPane>
|
||||
</items>
|
||||
</SplitPane>
|
||||
<BorderPane>
|
||||
<top>
|
||||
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Log">
|
||||
<BorderPane.margin>
|
||||
<Insets left="5.0" right="5.0" top="5.0" />
|
||||
</BorderPane.margin>
|
||||
</Text>
|
||||
</top>
|
||||
<center>
|
||||
<ListView prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
|
||||
</center>
|
||||
</BorderPane>
|
||||
</items>
|
||||
</SplitPane>
|
||||
<HBox id="HBox" alignment="CENTER_LEFT" spacing="5.0" VBox.vgrow="NEVER">
|
||||
<children>
|
||||
<Label fx:id="statusTxt" maxHeight="1.7976931348623157E308" maxWidth="-1.0" text="Done." HBox.hgrow="ALWAYS">
|
||||
<font>
|
||||
<Font size="11.0" fx:id="x3" />
|
||||
</font>
|
||||
<textFill>
|
||||
<Color blue="0.625" green="0.625" red="0.625" fx:id="x4" />
|
||||
</textFill>
|
||||
</Label>
|
||||
<ProgressBar fx:id="statusBar" disable="true" maxWidth="1.7976931348623157E308" prefHeight="20.0" progress="0.0" HBox.hgrow="ALWAYS" />
|
||||
<Label fx:id="statusPercentage" font="$x3" maxWidth="-1.0" text="0%" textFill="$x4" HBox.hgrow="NEVER" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
|
||||
</padding>
|
||||
</HBox>
|
||||
</children>
|
||||
</VBox>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="it.cavallium.SecondaryController">
|
||||
<children>
|
||||
<Label text="Secondary View" />
|
||||
<Button fx:id="secondaryButton" text="Switch to Primary View" onAction="#switchToPrimary" />
|
||||
<Button fx:id="secondaryButton" text="Close" onAction="#switchToPrimary" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
|
Loading…
Reference in New Issue
Block a user