Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync
This commit is contained in:
		@ -1,18 +1,31 @@
 | 
			
		||||
package org.hso.texturesyncclient.app
 | 
			
		||||
 | 
			
		||||
import org.hso.texturesyncclient.controller.RootController
 | 
			
		||||
import org.hso.texturesyncclient.controller.SettingsController
 | 
			
		||||
import org.hso.texturesyncclient.view.importView.ImportView
 | 
			
		||||
import org.hso.texturesyncclient.view.mainView.MainView
 | 
			
		||||
import org.hso.texturesyncclient.view.mainView.MainViewController
 | 
			
		||||
import org.hso.texturesyncclient.view.startupView.StartupView
 | 
			
		||||
import org.hso.texturesyncclient.view.startupView.StartupViewController
 | 
			
		||||
import tornadofx.App
 | 
			
		||||
 | 
			
		||||
class Main: App(MainView::class){
 | 
			
		||||
class Main: App(StartupView::class){
 | 
			
		||||
 | 
			
		||||
    val controller = RootController()
 | 
			
		||||
 | 
			
		||||
    private val svc: StartupViewController by inject()
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        // TODO get saved IP address, if found try to connect, else show StartupView
 | 
			
		||||
        SettingsController.init()
 | 
			
		||||
 | 
			
		||||
        if (SettingsController.serverAddressIsSet()) {
 | 
			
		||||
            //load settings in ui and try to connect
 | 
			
		||||
            println("serverAddress is set")
 | 
			
		||||
            svc.setServerAddress(SettingsController.getServerAddress())
 | 
			
		||||
            svc.btnConnectAction(SettingsController.getServerAddress())
 | 
			
		||||
        } else {
 | 
			
		||||
            println("serverAddress is not set")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
package org.hso.texturesyncclient.controller
 | 
			
		||||
 | 
			
		||||
import javafx.application.Platform
 | 
			
		||||
import javafx.collections.ObservableList
 | 
			
		||||
import javafx.stage.DirectoryChooser
 | 
			
		||||
import org.hso.texturesyncclient.controller.net.Connection
 | 
			
		||||
@ -7,6 +8,7 @@ import org.hso.texturesyncclient.model.GUIModel
 | 
			
		||||
import org.hso.texturesyncclient.model.Sha256
 | 
			
		||||
import org.hso.texturesyncclient.model.Texture
 | 
			
		||||
import org.hso.texturesyncclient.model.TextureFormat
 | 
			
		||||
import org.hso.texturesyncclient.view.importView.ImportView
 | 
			
		||||
import org.hso.texturesyncclient.view.importView.ImportViewController
 | 
			
		||||
import org.hso.texturesyncclient.view.mainView.MainView
 | 
			
		||||
import org.hso.texturesyncclient.view.mainView.MainViewController
 | 
			
		||||
@ -14,7 +16,6 @@ import org.hso.texturesyncclient.view.startupView.StartupView
 | 
			
		||||
import org.hso.texturesyncclient.view.startupView.StartupViewController
 | 
			
		||||
import tornadofx.Controller
 | 
			
		||||
import tornadofx.observable
 | 
			
		||||
import tornadofx.observableList
 | 
			
		||||
import java.net.InetAddress
 | 
			
		||||
import java.util.Calendar
 | 
			
		||||
import java.io.File
 | 
			
		||||
@ -30,25 +31,18 @@ class RootController : Controller() {
 | 
			
		||||
 | 
			
		||||
    private lateinit var con: Connection
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        /*var data = Texture()
 | 
			
		||||
        var img = con.getTexturePreview(data.textureHash)
 | 
			
		||||
        var test = GUIModel(data, img)
 | 
			
		||||
        test.exportItem.setOnAction {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        mvc.addElement(test)
 | 
			
		||||
 | 
			
		||||
        data = Texture()
 | 
			
		||||
        img = con.getTexturePreview(data.textureHash)
 | 
			
		||||
        test = GUIModel(data, img)
 | 
			
		||||
        test.exportItem.setOnAction {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        mvc.addElement(test)*/
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * calculate the resolution, get today's date -> upload to server
 | 
			
		||||
     * @param path the absolute path of the file on the client's system
 | 
			
		||||
@ -63,7 +57,7 @@ class RootController : Controller() {
 | 
			
		||||
        val bimg = ImageIO.read(File(path)) //image for obtaining resolution
 | 
			
		||||
        val resolution = Pair(bimg.height, bimg.width)
 | 
			
		||||
        val cal = Calendar.getInstance() //calendar obj with current time
 | 
			
		||||
        val hash =  Sha256(data)
 | 
			
		||||
        val hash = Sha256(data)
 | 
			
		||||
 | 
			
		||||
        //Todo free image
 | 
			
		||||
 | 
			
		||||
@ -79,18 +73,20 @@ class RootController : Controller() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize connection to server
 | 
			
		||||
     * Initialize connection to server and switch to MainView if connected
 | 
			
		||||
     * @param name server name as IP or domain
 | 
			
		||||
     */
 | 
			
		||||
    fun initConnection(name: String) {
 | 
			
		||||
        try {
 | 
			
		||||
            con = Connection(InetAddress.getByName(name))
 | 
			
		||||
            con.ping()
 | 
			
		||||
            println("Connection successful")
 | 
			
		||||
 | 
			
		||||
            // TODO store server ip for next start
 | 
			
		||||
            println("Connection to Server successful")
 | 
			
		||||
            SettingsController.setServerAddress(name)
 | 
			
		||||
            switchStartupToMain()
 | 
			
		||||
            println("swithing to MainView @ initCon")
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            println(e)
 | 
			
		||||
            println("Connection to Server NOT successful")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
@ -112,10 +108,29 @@ class RootController : Controller() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    fun switchToMainView(){
 | 
			
		||||
        find(StartupView::class).replaceWith(MainView::class, sizeToScene = true, centerOnScreen = true)
 | 
			
		||||
    fun switchStartupToMain() {
 | 
			
		||||
        Platform.runLater {
 | 
			
		||||
            find(StartupView::class).replaceWith(MainView::class, sizeToScene = true, centerOnScreen = true)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // These runLater calls should be unnecessary
 | 
			
		||||
    fun switchMainToImport() {
 | 
			
		||||
        Platform.runLater {
 | 
			
		||||
            find(MainView::class).replaceWith(ImportView::class, sizeToScene = true, centerOnScreen = true)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun switchImportToMain() {
 | 
			
		||||
        Platform.runLater {
 | 
			
		||||
            find(ImportView::class).replaceWith(MainView::class, sizeToScene = true, centerOnScreen = true)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * save the texture file to a local directory
 | 
			
		||||
     * @param data the texture as meta element
 | 
			
		||||
     */
 | 
			
		||||
    fun exportTexture(data: Texture) {
 | 
			
		||||
        val directoryChooser = DirectoryChooser()
 | 
			
		||||
        directoryChooser.title = "Export Verzeichnis wählen"
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,79 @@
 | 
			
		||||
package org.hso.texturesyncclient.controller
 | 
			
		||||
 | 
			
		||||
import java.io.*
 | 
			
		||||
import java.util.Properties
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SettingsController {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
 | 
			
		||||
        private lateinit var serverAddress: String
 | 
			
		||||
 | 
			
		||||
        private lateinit var props: Properties
 | 
			
		||||
 | 
			
		||||
        private val userHome = System.getProperty("user.home")
 | 
			
		||||
        private val osName = System.getProperty("os.name")
 | 
			
		||||
 | 
			
		||||
        private lateinit var dirPath: String //path to settings file
 | 
			
		||||
        private lateinit var settingsFile: File //settings file
 | 
			
		||||
 | 
			
		||||
        private const val defaultAddressValue: String = " "
 | 
			
		||||
 | 
			
		||||
        fun init() {
 | 
			
		||||
            props = Properties()
 | 
			
		||||
 | 
			
		||||
            dirPath = if (osName.contains("Windows")) {
 | 
			
		||||
                "$userHome/Documents/TextureSync"
 | 
			
		||||
            } else {
 | 
			
		||||
                "$userHome/.TextureSync"
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            settingsFile = File("$dirPath/config.xml") //open Settings file
 | 
			
		||||
 | 
			
		||||
            if (!settingsFile.exists()) {
 | 
			
		||||
                println("settings not found! Will create new one")
 | 
			
		||||
                File(dirPath).mkdir()
 | 
			
		||||
                settingsFile.createNewFile()
 | 
			
		||||
                serverAddress = defaultAddressValue //load default value
 | 
			
		||||
                saveSettings()
 | 
			
		||||
            } else {
 | 
			
		||||
                println("settings found")
 | 
			
		||||
                loadSettings()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun serverAddressIsSet(): Boolean {
 | 
			
		||||
            if (serverAddress == defaultAddressValue) {
 | 
			
		||||
                return false
 | 
			
		||||
            }
 | 
			
		||||
            return true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private fun loadSettings() {
 | 
			
		||||
            val inputStream: InputStream
 | 
			
		||||
            inputStream = FileInputStream(settingsFile)
 | 
			
		||||
            props.loadFromXML(inputStream)
 | 
			
		||||
            serverAddress = props.getProperty("serverAddress")
 | 
			
		||||
            inputStream.close()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private fun saveSettings() {
 | 
			
		||||
            val outputStream: OutputStream
 | 
			
		||||
            props.setProperty("serverAddress", serverAddress)
 | 
			
		||||
            outputStream = FileOutputStream(settingsFile)
 | 
			
		||||
            props.storeToXML(outputStream, "TextureSync settings")
 | 
			
		||||
            outputStream.close()
 | 
			
		||||
            println("settings saved")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun getServerAddress(): String {
 | 
			
		||||
            return serverAddress
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun setServerAddress(serverAddress: String) {
 | 
			
		||||
            this.serverAddress = serverAddress
 | 
			
		||||
            saveSettings()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -24,6 +24,7 @@ class ImportViewController : Controller() {
 | 
			
		||||
 | 
			
		||||
    fun btnImportAction() {
 | 
			
		||||
        rootc.importTexture(iv.tfFilePath.text, iv.tfName.text, iv.cvTags.chips)
 | 
			
		||||
        rootc.switchImportToMain()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun validateImport() {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,10 @@
 | 
			
		||||
package org.hso.texturesyncclient.view.mainView
 | 
			
		||||
 | 
			
		||||
import com.jfoenix.controls.JFXButton
 | 
			
		||||
import com.jfoenix.controls.JFXChipView
 | 
			
		||||
import javafx.geometry.Insets
 | 
			
		||||
import javafx.geometry.Orientation
 | 
			
		||||
import javafx.geometry.Pos
 | 
			
		||||
import javafx.scene.control.Label
 | 
			
		||||
import javafx.scene.image.Image
 | 
			
		||||
import javafx.scene.layout.Background
 | 
			
		||||
@ -16,6 +18,7 @@ class DetailView: View() {
 | 
			
		||||
    val preview = Preview3D()
 | 
			
		||||
    val metaLabel = Label("Auflösung: 8MP\nName: Texture.png\nAndere: was anderes")
 | 
			
		||||
    val cvTags = JFXChipView<String>()
 | 
			
		||||
    val btnImport = JFXButton("+")
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        // set a default texture
 | 
			
		||||
@ -39,14 +42,40 @@ class DetailView: View() {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            field {
 | 
			
		||||
                minHeight = 145.0
 | 
			
		||||
                add(cvTags)
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            field {
 | 
			
		||||
                hbox(alignment = Pos.CENTER_RIGHT) {
 | 
			
		||||
                    add(btnImport)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // TODO add "Import" Btn
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        style {
 | 
			
		||||
            cvTags.minHeight = 135.0
 | 
			
		||||
            cvTags.paddingAll = 3.0
 | 
			
		||||
            cvTags.style = "-fx-background-color: #3c3f41; -fx-text-inner-color: #b15b2e;"
 | 
			
		||||
 | 
			
		||||
            btnImport.buttonType = JFXButton.ButtonType.RAISED
 | 
			
		||||
            // TODO move this to a css file
 | 
			
		||||
            btnImport.style = "-fx-background-color: #F1F1F1;\n" +
 | 
			
		||||
                    "    -fx-background-radius: 50px;\n" +
 | 
			
		||||
                    "    -fx-pref-height: 50px;\n" +
 | 
			
		||||
                    "    -fx-pref-width: 50px;\n" +
 | 
			
		||||
                    "    -fx-min-width: -fx-pref-width;\n" +
 | 
			
		||||
                    "    -fx-max-width: -fx-pref-width;\n" +
 | 
			
		||||
                    "    -fx-min-height: -fx-pref-height;\n" +
 | 
			
		||||
                    "    -fx-max-height: -fx-pref-height;\n" +
 | 
			
		||||
                    "-jfx-button-type: RAISED;"
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        btnImport.setOnAction {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -10,11 +10,11 @@ import tornadofx.*
 | 
			
		||||
class FolderView : View("FolderView"){
 | 
			
		||||
 | 
			
		||||
    override val root = flowpane {
 | 
			
		||||
        hgap = 10.0
 | 
			
		||||
        vgap = 10.0
 | 
			
		||||
        paddingAll = 5.0
 | 
			
		||||
        hgap = 15.0
 | 
			
		||||
        vgap = 15.0
 | 
			
		||||
        paddingAll = 12.0
 | 
			
		||||
        prefWidth = 732.0
 | 
			
		||||
        prefHeight = 1000.0
 | 
			
		||||
        prefHeight = 401.0
 | 
			
		||||
        background = Background(BackgroundFill(Paint.valueOf("#cfcfcf"), CornerRadii.EMPTY, Insets.EMPTY))
 | 
			
		||||
        //background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ package org.hso.texturesyncclient.view.mainView
 | 
			
		||||
import com.jfoenix.controls.JFXChipView
 | 
			
		||||
import com.jfoenix.controls.JFXSpinner
 | 
			
		||||
import javafx.geometry.Insets
 | 
			
		||||
import javafx.scene.control.ScrollPane
 | 
			
		||||
 | 
			
		||||
import javafx.scene.layout.Background
 | 
			
		||||
import javafx.scene.layout.BackgroundFill
 | 
			
		||||
@ -26,17 +27,29 @@ class MainView : View() {
 | 
			
		||||
        maxHeight = 500.0
 | 
			
		||||
 | 
			
		||||
        left = vbox {
 | 
			
		||||
            prefWidth = 750.0
 | 
			
		||||
            background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY))
 | 
			
		||||
            add(cvSearch)
 | 
			
		||||
            scrollpane {
 | 
			
		||||
                add(folderView.root)
 | 
			
		||||
            anchorpane {
 | 
			
		||||
                scrollpane {
 | 
			
		||||
                    this.fitToParentSize()
 | 
			
		||||
                    this.vbarPolicy = ScrollPane.ScrollBarPolicy.ALWAYS
 | 
			
		||||
                    add(folderView.root)
 | 
			
		||||
                }
 | 
			
		||||
                add(spinnerSearch)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        right = detailView.root
 | 
			
		||||
 | 
			
		||||
        style {
 | 
			
		||||
            spinnerSearch.isVisible = false
 | 
			
		||||
            spinnerSearch.anchorpaneConstraints {
 | 
			
		||||
                topAnchor = 150
 | 
			
		||||
                bottomAnchor = 150
 | 
			
		||||
                leftAnchor = 150
 | 
			
		||||
                rightAnchor = 150
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            cvSearch.paddingAll = 7.0
 | 
			
		||||
            cvSearch.minHeight = 70.0
 | 
			
		||||
@ -52,6 +65,10 @@ class MainView : View() {
 | 
			
		||||
            mvc.updateTags()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        detailView.btnImport.setOnAction {
 | 
			
		||||
            mvc.btnImportAction()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -3,14 +3,8 @@ package org.hso.texturesyncclient.view.mainView
 | 
			
		||||
import javafx.collections.ObservableList
 | 
			
		||||
import javafx.scene.image.Image
 | 
			
		||||
import org.hso.texturesyncclient.model.GUIModel
 | 
			
		||||
import org.hso.texturesyncclient.model.TextureFormat
 | 
			
		||||
import tornadofx.Controller
 | 
			
		||||
import javafx.stage.DirectoryChooser
 | 
			
		||||
import org.hso.texturesyncclient.controller.RootController
 | 
			
		||||
import tornadofx.clear
 | 
			
		||||
import javax.swing.JColorChooser.showDialog
 | 
			
		||||
import java.io.File
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MainViewController : Controller() {
 | 
			
		||||
 | 
			
		||||
@ -25,7 +19,6 @@ class MainViewController : Controller() {
 | 
			
		||||
    private val metaLabel = mv.detailView.metaLabel
 | 
			
		||||
    private val cvTags = mv.detailView.cvTags
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // FolderView functions
 | 
			
		||||
    fun addElement(element: GUIModel) {
 | 
			
		||||
        folderView.children.add(element)
 | 
			
		||||
@ -50,42 +43,17 @@ class MainViewController : Controller() {
 | 
			
		||||
        cvTags.chips.addAll(chips)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // update the tags for the selected element
 | 
			
		||||
    fun updateTags() {
 | 
			
		||||
        println(cvTags.chips)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * save the texture file to r
 | 
			
		||||
     * @param data the file as a byte array
 | 
			
		||||
     * @param name name for the file
 | 
			
		||||
     * @param format specific file format. jpeg or png
 | 
			
		||||
     */
 | 
			
		||||
    fun exportTexture(data: ByteArray, name: String, format : TextureFormat){
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        val directoryChooser = DirectoryChooser()
 | 
			
		||||
 | 
			
		||||
        directoryChooser.title = "Export Verzeichnis wählen"
 | 
			
		||||
 | 
			
		||||
        // TODO directoryChooser.setInitialDirectory(new File(System.getProperty("user.home")))
 | 
			
		||||
 | 
			
		||||
        val dir = directoryChooser.showDialog(primaryStage)
 | 
			
		||||
 | 
			
		||||
        if (dir != null) {
 | 
			
		||||
 | 
			
		||||
        //copy data (bytesarray) with name and extension to dir
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // DetailView actions
 | 
			
		||||
 | 
			
		||||
    fun cvSearchAction(tags: ObservableList<String>) {
 | 
			
		||||
        var previewList = arrayListOf<GUIModel>()
 | 
			
		||||
 | 
			
		||||
        // show spinner, block ui
 | 
			
		||||
        folderView.children.clear()
 | 
			
		||||
        folderView.children.add(mv.spinnerSearch)
 | 
			
		||||
        mv.spinnerSearch.isVisible = true
 | 
			
		||||
        mv.cvSearch.isDisable = true
 | 
			
		||||
 | 
			
		||||
@ -93,13 +61,14 @@ class MainViewController : Controller() {
 | 
			
		||||
             previewList = rootc.search(tags)
 | 
			
		||||
         } ui {
 | 
			
		||||
             // when search finished
 | 
			
		||||
             folderView.children.clear()
 | 
			
		||||
             addAllElements(previewList)
 | 
			
		||||
             mv.spinnerSearch.isVisible = false
 | 
			
		||||
             mv.cvSearch.isDisable = false
 | 
			
		||||
         }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    fun btnImportAction() {
 | 
			
		||||
        rootc.switchMainToImport()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -10,6 +10,11 @@ class StartupViewController : Controller() {
 | 
			
		||||
    private val sv = find(StartupView::class)
 | 
			
		||||
    private val rootc = find(RootController::class)
 | 
			
		||||
 | 
			
		||||
    fun setServerAddress(address: String){
 | 
			
		||||
        sv.tfServerIP.text = address
 | 
			
		||||
        sv.tfServerIP.isFocusTraversable = false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun btnConnectAction(name: String) {
 | 
			
		||||
        sv.labelStatus.text = "Verbinden ..."
 | 
			
		||||
        sv.tfServerIP.isEditable = false
 | 
			
		||||
@ -25,7 +30,6 @@ class StartupViewController : Controller() {
 | 
			
		||||
            sv.tfServerIP.isEditable = true
 | 
			
		||||
            sv.btnConnect.isDisable = false
 | 
			
		||||
            sv.tfServerIP.clear()
 | 
			
		||||
            rootc.switchToMainView()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user