Code Sketch


sniper_0718
By: Mhalsakant School
Category: Art
import javax.swing._
import java.awt._
import java.awt.event._
import java.io.File
import javax.imageio.ImageIO
import scala.collection.mutable

// Global state for Kojo environment
val registeredUsers = mutable.Map[String, String](
  "bhimraj" -> "praxnya",
  "user1" -> "123", 
  "user2" -> "456"
)
val onlineUsers = mutable.Set[String]()
val friendRequests = mutable.Map[String, mutable.Set[String]]() 
val friendsMap = mutable.Map[String, mutable.Set[String]]()
val userPersonalPosts = mutable.Map[String, mutable.ListBuffer[String]]()
val profileImages = mutable.Map[String, ImageIcon]()
val notifications = mutable.Map[String, mutable.ListBuffer[String]]()
val chatHistories = mutable.Map[(String, String), mutable.ListBuffer[(String, String)]]()

class LoginFrame extends JFrame {
  setTitle("Kojo Social - Login")
  setResizable(false)
  setSize(400, 240)
  setLocationRelativeTo(null)
  setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)

  val idField = new JTextField("bhimraj", 15)
  val passField = new JPasswordField("praxnya", 15)
  val loginButton = new JButton("Login / Register")
  val errorLabel = new JLabel("")
  errorLabel.setForeground(Color.RED)

  val panel = new JPanel()
  panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS))
  panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20))

  val idPanel = new JPanel(new FlowLayout(FlowLayout.LEFT))
  idPanel.add(new JLabel("ID:   "))
  idPanel.add(idField)

  val passPanel = new JPanel(new FlowLayout(FlowLayout.LEFT))
  passPanel.add(new JLabel("Pass: "))
  passPanel.add(passField)

  panel.add(idPanel)
  panel.add(Box.createVerticalStrut(5))
  panel.add(passPanel)
  panel.add(Box.createVerticalStrut(15))
  panel.add(loginButton)
  panel.add(Box.createVerticalStrut(10))
  panel.add(errorLabel)

  add(panel)

  loginButton.addActionListener(new ActionListener {
    override def actionPerformed(e: ActionEvent): Unit = {
      val id = idField.getText.trim
      val pass = new String(passField.getPassword).trim
      if (id.nonEmpty && pass.nonEmpty) {
        if (registeredUsers.contains(id) && registeredUsers(id) != pass) {
          errorLabel.setText("Incorrect Password!")
        } else {
          registeredUsers(id) = pass
          onlineUsers += id
          new Dashboard(id).setVisible(true)
          dispose()
        }
      } else {
        errorLabel.setText("Please fill all fields!")
      }
    }
  })
}

class Dashboard(currentUserId: String) extends JFrame {
  setTitle("Kojo Social Dashboard - Logged in as: " + currentUserId)
  setSize(1150, 680)
  setLocationRelativeTo(null)
  setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
  setLayout(new BorderLayout())

  var selectedTargetUser: String = ""

  // 1. Left Column: Active Users (Online)
  val usersListPanel = new JPanel()
  usersListPanel.setLayout(new BoxLayout(usersListPanel, BoxLayout.Y_AXIS))
  val usersScroll = new JScrollPane(usersListPanel)
  usersScroll.setPreferredSize(new Dimension(240, 600))

  // 2. Center Column: Live Chat
  val centerPanel = new JPanel()
  centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS))
  centerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10))
  
  val chatTitleLbl = new JLabel("Select a user from left to Start Live Chat")
  chatTitleLbl.setFont(new Font("Arial", Font.BOLD, 13))
  
  val chatArea = new JTextArea(16, 30)
  chatArea.setEditable(false)
  val chatScroll = new JScrollPane(chatArea)
  
  val msgField = new JTextField(20)
  val sendMsgBtn = new JButton("Send Message")
  val msgPanel = new JPanel(new FlowLayout(FlowLayout.LEFT))
  msgPanel.add(msgField)
  msgPanel.add(sendMsgBtn)
  msgPanel.setVisible(false)

  centerPanel.add(chatTitleLbl)
  centerPanel.add(Box.createVerticalStrut(10))
  centerPanel.add(chatScroll)
  centerPanel.add(Box.createVerticalStrut(10))
  centerPanel.add(msgPanel)

  // 3. Right Column: Friend Requests, Upload Local Photo & Private Posts
  val rightPanel = new JPanel()
  rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS))
  rightPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10))
  val rightScroll = new JScrollPane(rightPanel)
  rightScroll.setPreferredSize(new Dimension(380, 600))

  // Timer to poll live notifications & chat updates
  val timer = new Timer(1000, new ActionListener {
    override def actionPerformed(e: ActionEvent): Unit = {
      refreshOnlineUsers()
      checkNotifications()
      if (selectedTargetUser.nonEmpty) {
        reloadChatArea()
      }
    }
  })
  timer.start()

  def checkNotifications(): Unit = {
    notifications.get(currentUserId) match {
      case Some(msgs) if msgs.nonEmpty =>
        for (m <- msgs) {
          JOptionPane.showMessageDialog(this, m, "Live Notification", JOptionPane.INFORMATION_MESSAGE)
        }
        msgs.clear()
      case _ =>
    }
  }

  def reloadChatArea(): Unit = {
    if (selectedTargetUser.nonEmpty) {
      val chatKey = if (currentUserId < selectedTargetUser) (currentUserId, selectedTargetUser) else (selectedTargetUser, currentUserId)
      val history = chatHistories.getOrElse(chatKey, mutable.ListBuffer())
      chatArea.setText(history.map { case (sender, msg) => sender + ": " + msg }.mkString("\n"))
    }
  }

  def refreshOnlineUsers(): Unit = {
    usersListPanel.removeAll()
    val titleLbl = new JLabel("Active Users (Online):")
    titleLbl.setFont(new Font("Arial", Font.BOLD, 13))
    usersListPanel.add(titleLbl)
    usersListPanel.add(Box.createVerticalStrut(10))
    
    for (user <- onlineUsers) {
      val displayName = if (user == currentUserId) user + " (You)" else user
      val btn = new JButton(displayName)
      btn.setHorizontalAlignment(SwingConstants.LEFT)
      btn.setMaximumSize(new Dimension(220, 30))
      
      btn.addActionListener(new ActionListener {
        override def actionPerformed(e: ActionEvent): Unit = {
          if (user != currentUserId) {
            selectedTargetUser = user
            chatTitleLbl.setText("Live Chat with: " + user)
            msgPanel.setVisible(true)
            reloadChatArea()
          } else {
            JOptionPane.showMessageDialog(usersListPanel, "This is your own profile.", "Info", JOptionPane.INFORMATION_MESSAGE)
          }
        }
      })
      usersListPanel.add(btn)
      usersListPanel.add(Box.createVerticalStrut(5))
    }
    usersListPanel.revalidate()
    usersListPanel.repaint()
  }

  def setupRightPanel(): Unit = {
    rightPanel.removeAll()

    // Upload Local Photo Button (Computer varun photo select karnyasathi)
    val uploadPhotoBtn = new JButton("Upload Photo from Computer")
    uploadPhotoBtn.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        val fileChooser = new JFileChooser()
        val result = fileChooser.showOpenDialog(rightPanel)
        if (result == JFileChooser.APPROVE_OPTION) {
          val file = fileChooser.getSelectedFile
          try {
            val img = ImageIO.read(file)
            if (img != null) {
              profileImages(currentUserId) = new ImageIcon(img)
              JOptionPane.showMessageDialog(rightPanel, "Photo uploaded successfully!")
            } else {
              JOptionPane.showMessageDialog(rightPanel, "Selected file is not a valid image!", "Error", JOptionPane.ERROR_MESSAGE)
            }
          } catch {
            case _: Throwable => JOptionPane.showMessageDialog(rightPanel, "Failed to load image!", "Error", JOptionPane.ERROR_MESSAGE)
          }
        }
      }
    })
    rightPanel.add(uploadPhotoBtn)
    rightPanel.add(Box.createVerticalStrut(15))

    // Section 1: Friend Requests Section
    val frTitle = new JLabel("Friend Requests:")
    frTitle.setFont(new Font("Arial", Font.BOLD, 13))
    rightPanel.add(frTitle)
    rightPanel.add(Box.createVerticalStrut(5))

    val reqButton = new JButton("Send Friend Request to Selected User")
    reqButton.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        if (selectedTargetUser.nonEmpty) {
          friendRequests.getOrElseUpdate(selectedTargetUser, mutable.Set()) += currentUserId
          reqButton.setText("Request Sent")
          reqButton.setEnabled(false)
          JOptionPane.showMessageDialog(rightPanel, "Friend request sent to " + selectedTargetUser + "!")
        } else {
          JOptionPane.showMessageDialog(rightPanel, "Please select a user from the left column first!")
        }
      }
    })
    rightPanel.add(reqButton)

    // Incoming Requests
    rightPanel.add(Box.createVerticalStrut(10))
    val incomingLbl = new JLabel("Incoming Requests:")
    incomingLbl.setFont(new Font("Arial", Font.BOLD, 11))
    rightPanel.add(incomingLbl)

    val myRecvReqs = friendRequests.getOrElse(currentUserId, mutable.Set())
    for (requester <- myRecvReqs) {
      val reqPanel = new JPanel(new FlowLayout(FlowLayout.LEFT))
      reqPanel.add(new JLabel(requester))
      val acceptBtn = new JButton("Accept")
      val rejectBtn = new JButton("Reject")

      acceptBtn.addActionListener(new ActionListener {
        override def actionPerformed(e: ActionEvent): Unit = {
          myRecvReqs -= requester
          friendsMap.getOrElseUpdate(currentUserId, mutable.Set()) += requester
          friendsMap.getOrElseUpdate(requester, mutable.Set()) += currentUserId
          notifications.getOrElseUpdate(requester, mutable.ListBuffer()) += (currentUserId + " accepted your friend request!")
          JOptionPane.showMessageDialog(rightPanel, "You accepted " + requester + "'s request!")
          setupRightPanel()
        }
      })

      rejectBtn.addActionListener(new ActionListener {
        override def actionPerformed(e: ActionEvent): Unit = {
          myRecvReqs -= requester
          notifications.getOrElseUpdate(requester, mutable.ListBuffer()) += (currentUserId + " rejected your friend request.")
          setupRightPanel()
        }
      })

      reqPanel.add(acceptBtn)
      reqPanel.add(rejectBtn)
      rightPanel.add(reqPanel)
    }

    // Section 2: Personal Posts
    rightPanel.add(Box.createVerticalStrut(15))
    val myPostTitle = new JLabel("My Personal Posts:")
    myPostTitle.setFont(new Font("Arial", Font.BOLD, 12))
    rightPanel.add(myPostTitle)
    rightPanel.add(Box.createVerticalStrut(5))

    val postInput = new JTextField(18)
    val addPostBtn = new JButton("Add Post")
    val postInputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT))
    postInputPanel.add(postInput)
    postInputPanel.add(addPostBtn)
    rightPanel.add(postInputPanel)

    val myPostsArea = new JTextArea(7, 25)
    myPostsArea.setEditable(false)

    def reloadMyPosts(): Unit = {
      val pList = userPersonalPosts.getOrElse(currentUserId, mutable.ListBuffer())
      myPostsArea.setText(pList.mkString("\n"))
    }
    reloadMyPosts()

    addPostBtn.addActionListener(new ActionListener {
      override def actionPerformed(e: ActionEvent): Unit = {
        val postTxt = postInput.getText.trim
        if (postTxt.nonEmpty) {
          userPersonalPosts.getOrElseUpdate(currentUserId, mutable.ListBuffer()) += ("- " + postTxt)
          postInput.setText("")
          reloadMyPosts()
        }
      }
    })

    rightPanel.add(Box.createVerticalStrut(5))
    rightPanel.add(new JScrollPane(myPostsArea))

    rightPanel.revalidate()
    rightPanel.repaint()
  }

  setupRightPanel()

  // Send Message Action for Live Chat
  val sendAction = new ActionListener {
    override def actionPerformed(e: ActionEvent): Unit = {
      val text = msgField.getText.trim
      if (text.nonEmpty && selectedTargetUser.nonEmpty) {
        val chatKey = if (currentUserId < selectedTargetUser) (currentUserId, selectedTargetUser) else (selectedTargetUser, currentUserId)
        val history = chatHistories.getOrElseUpdate(chatKey, mutable.ListBuffer[(String, String)]())
        history += ((currentUserId, text))
        reloadChatArea()
        msgField.setText("")
      }
    }
  }

  sendMsgBtn.addActionListener(sendAction)
  msgField.addActionListener(sendAction)

  add(usersScroll, BorderLayout.WEST)
  add(centerPanel, BorderLayout.CENTER)
  add(rightScroll, BorderLayout.EAST)

  refreshOnlineUsers()
}

// Start Login Window
SwingUtilities.invokeLater(new Runnable {
  def run(): Unit = {
    new LoginFrame().setVisible(true)
  }
})