Browse Source

add sample messenger example

Ethosa 3 years ago
parent
commit
42fbab61ad

+ 14 - 0
examples/sample_messenger/main.nim

@@ -0,0 +1,14 @@
+# --- Sample messenger example --- #
+import
+  nodesnim,
+  scenes/enter,
+  scenes/chat
+
+
+when isMainModule:
+  Window("Client", 320, 640)
+
+
+  addScene(chat_scene)
+  addMainScene(enter_scene)
+  windowLaunch()

+ 1 - 0
examples/sample_messenger/nim.cfg

@@ -0,0 +1 @@
+--path:"../../src"

+ 2 - 0
examples/sample_messenger/readme.md

@@ -0,0 +1,2 @@
+# Sample messenger
+

+ 65 - 0
examples/sample_messenger/scenes/chat.nim

@@ -0,0 +1,65 @@
+import
+  ../server_api/api,
+  asyncdispatch,
+  httpclient,
+  nodesnim,
+  json
+
+
+var
+  thr: Thread[tuple[scene: ptr SceneRef, username: ptr string, timed_chat: ptr seq[JsonNode]]]
+  gradient = GradientDrawable()
+
+gradient.setCornerColors(Color("#C9D6FF"), Color("#C9D6FF"), Color("#E2E2E2"), Color("#E2E2E2"))
+
+Input.addKeyAction("send", 13)  # Enter
+
+
+build:
+  - Scene (chat_scene):
+    call rename("Chat")
+    - Control background:
+      call rename("background")
+      call setBackground(gradient)
+      call setSizeAnchor(1, 1)
+
+      - Label chat:
+        call rename("chat")
+        call setSizeAnchor(1, 1)
+
+      - EditText message:
+        call setSizeAnchor(0.95, 0.15)
+        call setAnchor(0.5, 1, 0.5, 1.2)
+        call setStyle(style({
+          border-radius: 8,
+          border-detail: 8,
+          background-color: rgba(50, 60, 70, 0.5)
+          }))
+
+
+proc listenChat(arg: tuple[scene: ptr SceneRef, username: ptr string, timed_chat: ptr seq[JsonNode]]) {.thread.} =
+  var client = newAsyncHttpClient()
+  while true:
+    var
+      response = waitFor client.get("http://127.0.0.1:5000/getchat")
+      text = stext""
+    arg.timed_chat[] = parseJson(waitFor response.body())["data"].getElems
+
+    var i = 0
+    while i < arg.timed_chat[].len:
+      text &= (stext arg.timed_chat[][i].str & stext": " & stext arg.timed_chat[][i+1].str & stext("\n\n"))
+      inc i, 2
+    text.setColor(Color("#123"))
+    arg.scene[].getNode("background/chat").LabelRef.text = text
+
+    waitFor sleepAsync(100)
+
+
+background@onEnter(self):
+  createThread(thr, listenChat, (chat_scene.addr, username.addr, timed_chat.addr))
+
+background@onInput(self, event):
+  if Input.isActionJustPressed("send"):
+    if message.getText().len > 0:
+      sendMessage(message.getText())
+      message.setText("")

+ 75 - 0
examples/sample_messenger/scenes/enter.nim

@@ -0,0 +1,75 @@
+import
+  ../server_api/api,
+  asyncdispatch,
+  nodesnim
+
+
+var
+  gradient = GradientDrawable()
+
+gradient.setCornerColors(Color("#cac"), Color("#cac"), Color("#acc"), Color("#acc"))
+
+
+build:
+  - Scene (enter_scene):
+    call rename("Enter")
+  
+    - Control background:
+      call setSizeAnchor(1, 1)
+      call setBackground(gradient)
+  
+      - VBox input:
+        separator: 8
+        call setAnchor(0.5, 0.5, 0.5, 0.5)
+        call setChildAnchor(0.5, 0.5, 0.5, 0.5)
+        call resize(256, 256+64)
+        call setStyle(style({
+          border-radius: 8,
+          border-detail: 8,
+          background-color: rgba(100, 111, 122, 0.4)
+          }))
+  
+        - EditText login:
+          caret: false
+          call setTextAlign(0.5, 0.5, 0.5, 0.5)
+          call setStyle(style({
+            border-radius: 8,
+            border-detail: 8,
+            border-color: rgba(100, 111, 122, 0.4),
+            border-width: 1
+            }))
+        - Button send:
+          call setText("ENTER")
+
+
+send.normal_background.setStyle(style({
+  border-radius: 8,
+  border-detail: 8,
+  background-color: rgba(100, 111, 122, 0.4),
+  background-width: 1
+}))
+send.hover_background.setStyle(style({
+  border-radius: 8,
+  border-detail: 8,
+  background-color: rgba(100, 111, 122, 0.6),
+  background-width: 1
+}))
+send.press_background.setStyle(style({
+  border-radius: 8,
+  border-detail: 8,
+  background-color: rgba(100, 111, 122, 0.8),
+  background-width: 1
+}))
+
+
+login.hint = stext"Username"
+login.hint.setColor(Color("#ebebeb"))
+login.text.setColor(Color("#fff"))
+
+
+send@onClick(self, x, y):
+  username = login.getText()
+  if username.len > 0:
+    var response = waitFor enter()
+    if response:
+      changeScene("Chat")

+ 76 - 0
examples/sample_messenger/server.nim

@@ -0,0 +1,76 @@
+# author: Ethosa
+import
+  asyncdispatch,
+  db_sqlite,
+  akane
+
+
+proc userExists(connect: DbConn, username: string): bool =
+  for row in connect.rows(sql"SELECT username FROM users"):
+    if row[0] == username:
+      return true
+  return false
+
+proc addUser(connect: DbConn, username: string) =
+  if not connect.userExists(username):
+    connect.exec(sql"INSERT INTO users VALUES (?)", username)
+
+
+when isMainModule:
+  var db = open("users.db", "", "", "")
+
+  db.exec(sql"CREATE TABLE IF NOT EXISTS users (username text)")
+
+  proc main {.gcsafe.} =
+    var
+      server = newServer()
+      timed_chat = %*[]
+
+    server.pages:
+      "/":
+        await request.answer("Hello, World!")
+
+      startswith("/enter"):
+        var data = await parseQuery(request)
+        if "username" in data:
+          db.addUser($data["username"])
+          await request.sendJson(%*{"response": 0})
+        else:
+          await request.sendJson(
+            %*{
+              "response": 1,
+              "data": {
+                "text": "You need to specify a username!"
+              }})
+
+      startswith("/send"):
+        var data = await parseQuery(request)
+        if "username" in data and "msg" in data:
+          if db.userExists($data["username"]):
+            timed_chat.add(data["username"])
+            timed_chat.add(data["msg"])
+            await request.sendJson(%*{"response": 0})
+          else:
+            await request.sendJson(
+              %*{
+                "response": 1,
+                "data": {
+                  "text": "This user isn't registered!"
+                }})
+        else:
+          await request.sendJson(
+            %*{
+              "response": 1,
+              "data": {
+                "text": "You need to specify a msg and username!"
+              }})
+
+      startswith("/getchat"):
+        var response = %*{}
+        response["response"] = %0
+        response["data"] = timed_chat
+        await request.sendJson(response)
+
+
+    server.start()
+  main()

+ 11 - 0
examples/sample_messenger/server.nimble

@@ -0,0 +1,11 @@
+[Package]
+name = "server"
+author = "Ethosa"
+version = "0.1.0"
+description = "Sample server"
+license = "MIT"
+srcDir = ""
+
+[Deps]
+Requires: "nim >= 1.0.0"
+Requires: "akane >= 0.2.0"

+ 23 - 0
examples/sample_messenger/server_api/api.nim

@@ -0,0 +1,23 @@
+import
+  asyncdispatch,
+  httpclient,
+  json,
+  uri
+
+var
+  username*: string = ""
+  client = newAsyncHttpClient()
+  timed_chat*: seq[JsonNode]
+
+
+proc enter*(): Future[bool] {.async.} =
+  echo "http:/127.0.0.1:5000/enter?username=" & username
+  var
+    response = await client.get("http://127.0.0.1:5000/enter?" & encodeQuery({"username": username}))
+    data = parseJson(await response.body())
+  
+  return data["response"].num == 0
+
+
+proc sendMessage*(msg: string) =
+  var response = waitFor client.get("http://127.0.0.1:5000/send?" & encodeQuery({"username": username, "msg": msg}))

+ 23 - 18
src/nodesnim/nodescontrol/edittext.nim

@@ -22,12 +22,12 @@ import
 
 type
   EditTextRef* = ref object of LabelObj
-    hint: StyleText
+    hint*: StyleText
     caret_color: ColorRef
     caret_pos: uint32
     blink_time: uint8
     is_blink: bool
-    caret: bool
+    caret*: bool
     on_edit*: proc(pressed_key: string): void  ## This called when user press any key.
 
 const
@@ -54,7 +54,6 @@ proc EditText*(name: string = "EditText", hint: string = "Edit text ..."): EditT
   else:
     result.rect_min_size = result.hint.getTextSize()
   result.resize(result.rect_size.x, result.rect_size.y)
-  result.hint.render(result.rect_size, result.text_align)
 
 
 method draw*(self: EditTextRef, w, h: Glfloat) =
@@ -94,26 +93,33 @@ method draw*(self: EditTextRef, w, h: Glfloat) =
       yalign - caret[0].y - caret[1].float)
     glEnd()
 
-method setText*(self: EditTextRef, text: string, save_properties: bool = false) =
+
+template changeText( self, `text`, `save_properties`, t: untyped): untyped =
+  var st = stext(`text`)
+  if `self`.`t`.font.isNil():
+    `self`.`t`.font = standard_font
+  st.font = `self`.`t`.font
+
+  if `save_properties`:
+    for i in 0..<st.chars.len():
+      if i < `self`.`t`.len():
+        st.chars[i].color = `self`.`t`.chars[i].color
+        st.chars[i].underline = `self`.`t`.chars[i].underline
+  `self`.`t` = st
+  `self`.rect_min_size = `self`.`t`.getTextSize()
+  `self`.resize(`self`.rect_size.x, `self`.rect_size.y)
+  `self`.`t`.rendered = false
+
+method setText*(self: EditTextRef, t: string, save_properties: bool = false) =
   ## Changes text.
   ##
   ## Arguments:
   ## - `text` is a new Label text.
   ## - `save_properties` - saves old text properties, if `true`.
-  var st = stext(text)
-  if self.text.font.isNil():
-    self.text.font = standard_font
-  st.font = self.text.font
+  changeText(self, t, save_properties, text)
 
-  if save_properties:
-    for i in 0..<st.chars.len():
-      if i < self.text.len():
-        st.chars[i].color = self.text.chars[i].color
-        st.chars[i].underline = self.text.chars[i].underline
-  self.text = st
-  self.rect_min_size = self.text.getTextSize()
-  self.resize(self.rect_size.x, self.rect_size.y)
-  self.text.rendered = false
+method setHint*(self: EditTextRef, t: string, save_properties: bool = false) =
+  changeText(self, t, save_properties, hint)
 
 method handle*(self: EditTextRef, event: InputEvent, mouse_on: var NodeRef) =
   ## Handles user input. Thi uses in the `window.nim`.
@@ -149,7 +155,6 @@ method handle*(self: EditTextRef, event: InputEvent, mouse_on: var NodeRef) =
 
       elif event.key in pressed_keys:  # Normal chars
         if event.key_int == 8:  # Backspace
-          echo ($self.text, ", ", self.caret_pos)
           if self.caret_pos > 1 and self.caret_pos < self.text.len().uint32:
             self.setText(($self.text).toRunes()[0..self.caret_pos-2].`$` & ($self.text).toRunes()[self.caret_pos..^1].`$`)
             self.caret_pos -= 1