| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Towhed Messaging App</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .message-bubble { |
| max-width: 70%; |
| border-radius: 1rem; |
| padding: 0.75rem 1rem; |
| margin-bottom: 0.5rem; |
| position: relative; |
| } |
| .message-bubble.sent { |
| background-color: #3b82f6; |
| color: white; |
| align-self: flex-end; |
| } |
| .message-bubble.received { |
| background-color: #e5e7eb; |
| color: #1f2937; |
| align-self: flex-start; |
| } |
| .message-time { |
| font-size: 0.75rem; |
| opacity: 0.8; |
| margin-top: 0.25rem; |
| text-align: right; |
| } |
| .app-bar { |
| height: 56px; |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
| } |
| .chat-container { |
| height: calc(100vh - 56px - 64px); |
| overflow-y: auto; |
| } |
| .input-container { |
| height: 64px; |
| } |
| .floating-button { |
| position: fixed; |
| bottom: 1.5rem; |
| right: 1.5rem; |
| width: 56px; |
| height: 56px; |
| border-radius: 50%; |
| box-shadow: 0 4px 8px rgba(0,0,0,0.2); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| z-index: 10; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-100 font-sans"> |
| |
| <div id="login-screen" class="fixed inset-0 bg-white flex flex-col items-center justify-center p-6 z-20"> |
| <div class="w-full max-w-md"> |
| <div class="text-center mb-8"> |
| <h1 class="text-3xl font-bold text-blue-600">Towhed</h1> |
| <p class="text-gray-600 mt-2">Secure messaging with admin verification</p> |
| </div> |
| |
| <div class="bg-white rounded-lg shadow-md p-6"> |
| <h2 class="text-xl font-semibold mb-4 text-gray-800">Login</h2> |
| |
| <div class="mb-6"> |
| <label class="block text-gray-700 text-sm font-medium mb-2" for="code"> |
| Admin Verification Code |
| </label> |
| <input id="code" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Enter 6-digit code"> |
| <p class="text-xs text-gray-500 mt-1">You must get this code from the system admin</p> |
| </div> |
| |
| <button onclick="login()" class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition"> |
| Login |
| </button> |
| |
| <div class="mt-4 text-center"> |
| <p class="text-sm text-gray-600">Don't have an account? <span class="text-blue-600 cursor-pointer" onclick="showAdminPanel()">Request admin access</span></p> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="admin-panel" class="fixed inset-0 bg-white flex flex-col items-center justify-center p-6 z-20 hidden"> |
| <div class="w-full max-w-md"> |
| <div class="flex justify-between items-center mb-6"> |
| <button onclick="hideAdminPanel()" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-arrow-left"></i> |
| </button> |
| <h2 class="text-xl font-semibold text-gray-800">Admin Panel</h2> |
| <div class="w-6"></div> |
| </div> |
| |
| <div class="bg-white rounded-lg shadow-md p-6"> |
| <div class="mb-6"> |
| <label class="block text-gray-700 text-sm font-medium mb-2" for="admin-username"> |
| Admin Username |
| </label> |
| <input id="admin-username" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md mb-4 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Enter admin username"> |
| |
| <label class="block text-gray-700 text-sm font-medium mb-2" for="admin-password"> |
| Admin Password |
| </label> |
| <input id="admin-password" type="password" class="w-full px-3 py-2 border border-gray-300 rounded-md mb-4 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Enter admin password"> |
| |
| <label class="block text-gray-700 text-sm font-medium mb-2" for="generate-code"> |
| Generate Verification Code |
| </label> |
| <div class="flex mb-2"> |
| <input id="generated-code" type="text" readonly class="flex-1 px-3 py-2 border border-gray-300 rounded-l-md bg-gray-100" placeholder="Code will appear here"> |
| <button onclick="generateCode()" class="bg-blue-600 text-white px-4 py-2 rounded-r-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition"> |
| Generate |
| </button> |
| </div> |
| <div class="flex justify-between items-center"> |
| <span class="text-xs text-gray-500">Code expires in: <span id="code-expiry">5:00</span></span> |
| <button onclick="copyCode()" class="text-xs text-blue-600 hover:text-blue-800"> |
| <i class="fas fa-copy mr-1"></i>Copy Code |
| </button> |
| </div> |
| </div> |
| |
| <div class="mt-6 p-4 bg-blue-50 rounded-md"> |
| <h3 class="font-medium text-blue-800 mb-2">Admin Instructions</h3> |
| <p class="text-sm text-blue-700">1. Enter admin credentials</p> |
| <p class="text-sm text-blue-700">2. Click "Generate" to create a code</p> |
| <p class="text-sm text-blue-700">3. Share this code securely with authorized users</p> |
| <p class="text-sm text-blue-700">4. Each code is valid for 5 minutes only</p> |
| </div> |
| |
| <div class="mt-4 p-4 bg-gray-50 rounded-md"> |
| <h3 class="font-medium text-gray-800 mb-2">Recent Codes</h3> |
| <div id="recent-codes" class="text-sm text-gray-700"> |
| |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="app-interface" class="hidden"> |
| |
| <div class="app-bar bg-white flex flex-col fixed top-0 left-0 right-0 z-10"> |
| <div class="flex items-center px-4 py-2"> |
| <img src="https://via.placeholder.com/40" alt="Profile" class="rounded-full w-8 h-8 mr-3"> |
| <div> |
| <h1 class="font-medium">Towhed</h1> |
| <p class="text-xs text-gray-500">My Profile</p> |
| <div class="flex space-x-4 text-xs mt-1"> |
| <span><span class="font-medium">120</span> Posts</span> |
| <span><span class="font-medium">1.2K</span> Followers</span> |
| <span><span class="font-medium">350</span> Following</span> |
| </div> |
| </div> |
| <div class="ml-auto flex space-x-4"> |
| <button class="text-gray-600 hover:text-gray-900"> |
| <i class="fas fa-plus"></i> |
| </button> |
| <button class="text-gray-600 hover:text-gray-900"> |
| <i class="fas fa-ellipsis-v"></i> |
| </button> |
| </div> |
| </div> |
| <div class="flex border-b border-gray-200"> |
| <button onclick="showTab('posts')" class="flex-1 py-2 text-center font-medium text-blue-600 border-b-2 border-blue-600"> |
| Posts |
| </button> |
| <button onclick="showTab('messages')" class="flex-1 py-2 text-center font-medium text-gray-500 hover:text-gray-700"> |
| Messages |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="chat-container pt-24 pb-16 overflow-y-auto"> |
| |
| <div id="posts-tab" class="flex flex-col"> |
| |
| <div class="bg-white p-3 border-b border-gray-200 flex items-center"> |
| <span class="text-sm font-medium mr-2">Show:</span> |
| <select class="bg-gray-100 rounded-md px-2 py-1 text-sm focus:outline-none"> |
| <option>Posts from everyone</option> |
| <option>Posts from people I follow</option> |
| <option>My posts only</option> |
| </select> |
| </div> |
|
|
| |
| <div class="bg-white p-4 border-b border-gray-200"> |
| <div class="flex items-center mb-3"> |
| <img src="https://via.placeholder.com/40" alt="Profile" class="rounded-full w-10 h-10 mr-3"> |
| <input type="text" placeholder="What's on your mind?" class="flex-1 bg-gray-100 rounded-full py-2 px-4 focus:outline-none"> |
| </div> |
| <button class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700"> |
| Post |
| </button> |
| </div> |
|
|
| |
| <div class="bg-white p-4 mb-2 border-b border-gray-200"> |
| <div class="flex items-center justify-between mb-3"> |
| <div class="flex items-center"> |
| <img src="https://via.placeholder.com/40" alt="Profile" class="rounded-full w-10 h-10 mr-3"> |
| <div> |
| <h3 class="font-medium">User One</h3> |
| <p class="text-xs text-gray-500">2 hours ago</p> |
| </div> |
| </div> |
| <button class="text-xs bg-gray-100 hover:bg-gray-200 px-3 py-1 rounded-full"> |
| <i class="fas fa-user-plus mr-1"></i>Follow |
| </button> |
| </div> |
| <p class="mb-3">This is my first post on Towhed! Excited to share my thoughts here.</p> |
| <div class="flex justify-between text-gray-500 border-t border-gray-200 pt-2"> |
| <button class="flex items-center space-x-1 hover:text-blue-600"> |
| <i class="far fa-thumbs-up"></i> |
| <span>Like (12)</span> |
| </button> |
| <button class="flex items-center space-x-1 hover:text-red-600"> |
| <i class="far fa-thumbs-down"></i> |
| <span>Dislike (2)</span> |
| </button> |
| <button class="flex items-center space-x-1 hover:text-yellow-600"> |
| <i class="far fa-surprise"></i> |
| <span>Surprised (5)</span> |
| </button> |
| </div> |
| </div> |
|
|
| <div class="bg-white p-4 mb-2 border-b border-gray-200"> |
| <div class="flex items-center justify-between mb-3"> |
| <div class="flex items-center"> |
| <img src="https://via.placeholder.com/40" alt="Profile" class="rounded-full w-10 h-10 mr-3"> |
| <div> |
| <h3 class="font-medium">User Two</h3> |
| <p class="text-xs text-gray-500">5 hours ago</p> |
| </div> |
| </div> |
| <button class="text-xs bg-gray-100 hover:bg-gray-200 px-3 py-1 rounded-full"> |
| <i class="fas fa-user-plus mr-1"></i>Follow |
| </button> |
| </div> |
| <p class="mb-3">Check out this amazing view from my vacation!</p> |
| <img src="https://via.placeholder.com/600x300" alt="Post image" class="w-full rounded-md mb-3"> |
| <div class="flex justify-between text-gray-500 border-t border-gray-200 pt-2"> |
| <button class="flex items-center space-x-1 hover:text-blue-600"> |
| <i class="far fa-thumbs-up"></i> |
| <span>Like (45)</span> |
| </button> |
| <button class="flex items-center space-x-1 hover:text-red-600"> |
| <i class="far fa-thumbs-down"></i> |
| <span>Dislike (3)</span> |
| </button> |
| <button class="flex items-center space-x-1 hover:text-yellow-600"> |
| <i class="far fa-surprise"></i> |
| <span>Surprised (8)</span> |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="messages-tab" class="hidden flex flex-col space-y-2 px-4"> |
| |
| <div class="flex items-center my-4"> |
| <div class="flex-1 border-t border-gray-200"></div> |
| <span class="px-3 text-sm text-gray-500">Today</span> |
| <div class="flex-1 border-t border-gray-200"></div> |
| </div> |
| |
| |
| <div class="flex"> |
| <div class="message-bubble received"> |
| <p>Hello! Welcome to Towhed messaging app.</p> |
| <div class="message-time">10:30 AM</div> |
| </div> |
| </div> |
| |
| |
| <div class="flex justify-end"> |
| <div class="message-bubble sent"> |
| <p>Hi there! Thanks for the welcome.</p> |
| <div class="message-time">10:32 AM</div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="input-container bg-white fixed bottom-0 left-0 right-0 flex items-center px-4 border-t border-gray-200"> |
| <button class="text-gray-500 hover:text-gray-700 mr-2"> |
| <i class="fas fa-paperclip"></i> |
| </button> |
| <input type="text" placeholder="Type a message" class="flex-1 py-2 px-3 rounded-full border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500"> |
| <button class="ml-2 text-blue-600 hover:text-blue-800"> |
| <i class="fas fa-paper-plane"></i> |
| </button> |
| </div> |
|
|
| |
| <div class="floating-button bg-blue-600 text-white hover:bg-blue-700"> |
| <i class="fas fa-comment-medical"></i> |
| </div> |
| </div> |
|
|
| |
| <div id="kotlin-code" class="fixed inset-0 bg-white p-6 overflow-auto hidden z-30"> |
| <div class="max-w-4xl mx-auto"> |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-2xl font-bold text-gray-800">Towhed Kotlin Implementation</h2> |
| <button onclick="hideKotlinCode()" class="text-gray-500 hover:text-gray-700 p-2"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| |
| <div class="bg-gray-800 rounded-lg p-4 overflow-x-auto"> |
| <pre class="text-gray-100 text-sm"> |
| // MainActivity.kt |
| package com.example.towhed |
|
|
| import android.os.Bundle |
| import androidx.appcompat.app.AppCompatActivity |
| import androidx.recyclerview.widget.LinearLayoutManager |
| import com.example.towhed.databinding.ActivityMainBinding |
| import com.google.firebase.auth.FirebaseAuth |
| import com.google.firebase.firestore.FirebaseFirestore |
|
|
| class MainActivity : AppCompatActivity() { |
| private lateinit var binding: ActivityMainBinding |
| private lateinit var auth: FirebaseAuth |
| private lateinit var db: FirebaseFirestore |
| private lateinit var adapter: MessageAdapter |
| private val messages = mutableListOf<Message>() |
|
|
| override fun onCreate(savedInstanceState: Bundle?) { |
| super.onCreate(savedInstanceState) |
| binding = ActivityMainBinding.inflate(layoutInflater) |
| setContentView(binding.root) |
|
|
| auth = FirebaseAuth.getInstance() |
| db = FirebaseFirestore.getInstance() |
|
|
| // Check if user is logged in with admin code |
| if (auth.currentUser == null) { |
| startActivity(Intent(this, LoginActivity::class.java)) |
| finish() |
| return |
| } |
|
|
| setupRecyclerView() |
| setupListeners() |
| loadMessages() |
| } |
|
|
| private fun setupRecyclerView() { |
| adapter = MessageAdapter(messages) |
| binding.recyclerView.apply { |
| layoutManager = LinearLayoutManager(this@MainActivity) |
| adapter = this@MainActivity.adapter |
| } |
| } |
|
|
| private fun setupListeners() { |
| binding.sendButton.setOnClickListener { |
| val messageText = binding.messageInput.text.toString().trim() |
| if (messageText.isNotEmpty()) { |
| sendMessage(messageText) |
| binding.messageInput.text.clear() |
| } |
| } |
| } |
|
|
| private fun sendMessage(text: String) { |
| val message = Message( |
| text = text, |
| senderId = auth.currentUser?.uid ?: "", |
| timestamp = System.currentTimeMillis() |
| ) |
|
|
| db.collection("messages") |
| .add(message) |
| .addOnSuccessListener { |
| // Message sent successfully |
| } |
| .addOnFailureListener { |
| // Handle error |
| } |
| } |
|
|
| private fun loadMessages() { |
| db.collection("messages") |
| .orderBy("timestamp") |
| .addSnapshotListener { snapshot, error -> |
| if (error != null) return@addSnapshotListener |
|
|
| messages.clear() |
| snapshot?.documents?.forEach { doc -> |
| val message = doc.toObject(Message::class.java) |
| message?.let { messages.add(it) } |
| } |
| adapter.notifyDataSetChanged() |
| binding.recyclerView.scrollToPosition(messages.size - 1) |
| } |
| } |
| } |
|
|
| // LoginActivity.kt |
| package com.example.towhed |
|
|
| import android.content.Intent |
| import android.os.Bundle |
| import androidx.appcompat.app.AppCompatActivity |
| import com.example.towhed.databinding.ActivityLoginBinding |
| import com.google.firebase.auth.FirebaseAuth |
| import com.google.firebase.firestore.FirebaseFirestore |
|
|
| class LoginActivity : AppCompatActivity() { |
| private lateinit var binding: ActivityLoginBinding |
| private lateinit var auth: FirebaseAuth |
| private lateinit var db: FirebaseFirestore |
|
|
| override fun onCreate(savedInstanceState: Bundle?) { |
| super.onCreate(savedInstanceState) |
| binding = ActivityLoginBinding.inflate(layoutInflater) |
| setContentView(binding.root) |
|
|
| auth = FirebaseAuth.getInstance() |
| db = FirebaseFirestore.getInstance() |
|
|
| binding.loginButton.setOnClickListener { |
| val phone = binding.phoneInput.text.toString().trim() |
| val code = binding.codeInput.text.toString().trim() |
|
|
| if (phone.isEmpty() || code.isEmpty()) { |
| // Show error |
| return@setOnClickListener |
| } |
|
|
| verifyAdminCode(phone, code) |
| } |
|
|
| binding.adminLink.setOnClickListener { |
| startActivity(Intent(this, AdminActivity::class.java)) |
| } |
| } |
|
|
| private fun verifyAdminCode(code: String) { |
| db.collection("admin_codes") |
| .whereEqualTo("code", code) |
| .limit(1) |
| .get() |
| .addOnSuccessListener { doc -> |
| if (doc.exists() && doc.getString("code") == code) { |
| // Code is valid, proceed with authentication |
| authenticateUser(phone) |
| } else { |
| // Show invalid code error |
| } |
| } |
| .addOnFailureListener { |
| // Handle error |
| } |
| } |
|
|
| private fun authenticateUser(phone: String) { |
| // Implement phone authentication with Firebase |
| // On success: |
| startActivity(Intent(this, MainActivity::class.java)) |
| finish() |
| } |
| } |
|
|
| // AdminActivity.kt |
| package com.example.towhed |
|
|
| import android.os.Bundle |
| import androidx.appcompat.app.AppCompatActivity |
| import com.example.towhed.databinding.ActivityAdminBinding |
| import com.google.firebase.firestore.FirebaseFirestore |
| import java.util.* |
|
|
| class AdminActivity : AppCompatActivity() { |
| private lateinit var binding: ActivityAdminBinding |
| private lateinit var db: FirebaseFirestore |
|
|
| override fun onCreate(savedInstanceState: Bundle?) { |
| super.onCreate(savedInstanceState) |
| binding = ActivityAdminBinding.inflate(layoutInflater) |
| setContentView(binding.root) |
|
|
| db = FirebaseFirestore.getInstance() |
|
|
| binding.generateButton.setOnClickListener { |
| val phone = binding.phoneInput.text.toString().trim() |
| if (phone.isEmpty()) return@setOnClickListener |
|
|
| val code = generateRandomCode() |
| binding.codeOutput.setText(code) |
|
|
| saveAdminCode(phone, code) |
| } |
| } |
|
|
| private fun generateRandomCode(): String { |
| return (100000..999999).random().toString() |
| } |
|
|
| private fun saveAdminCode(phone: String, code: String) { |
| val data = hashMapOf( |
| "phone" to phone, |
| "code" to code, |
| "generatedAt" to System.currentTimeMillis() |
| ) |
|
|
| db.collection("admin_codes") |
| .document(phone) |
| .set(data) |
| .addOnSuccessListener { |
| // Code saved successfully |
| } |
| .addOnFailureListener { |
| // Handle error |
| } |
| } |
| } |
|
|
| // Message.kt |
| data class Message( |
| val text: String = "", |
| val senderId: String = "", |
| val timestamp: Long = 0L |
| ) |
|
|
| // MessageAdapter.kt |
| class MessageAdapter(private val messages: List<Message>) : |
| RecyclerView.Adapter<MessageAdapter.MessageViewHolder>() { |
| |
| inner class MessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
| fun bind(message: Message) { |
| // Bind message data to views |
| } |
| } |
|
|
| override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder { |
| val view = LayoutInflater.from(parent.context) |
| .inflate(R.layout.item_message, parent, false) |
| return MessageViewHolder(view) |
| } |
|
|
| override fun onBindViewHolder(holder: MessageViewHolder, position: Int) { |
| holder.bind(messages[position]) |
| } |
|
|
| override fun getItemCount(): Int = messages.size |
| } |
| </pre> |
| </div> |
| |
| <div class="mt-6 bg-blue-50 p-4 rounded-md"> |
| <h3 class="font-medium text-blue-800 mb-2">Implementation Notes:</h3> |
| <ul class="list-disc pl-5 text-blue-700 space-y-1"> |
| <li>Uses Firebase Authentication for user management</li> |
| <li>Firestore database stores messages and admin codes</li> |
| <li>Admin codes are generated randomly and stored</li> |
| <li>Users must provide exact admin code to login</li> |
| <li>Real-time messaging with Firestore listeners</li> |
| <li>Clean architecture with separate activities</li> |
| </ul> |
| </div> |
| |
| <button onclick="hideKotlinCode()" class="mt-6 w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition"> |
| Close Code View |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="fixed bottom-4 left-4 z-10"> |
| <button onclick="showKotlinCode()" class="bg-gray-800 text-white py-2 px-4 rounded-md hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition flex items-center"> |
| <i class="fas fa-code mr-2"></i> |
| View Kotlin Code |
| </button> |
| </div> |
|
|
| <script> |
| |
| function showAdminPanel() { |
| document.getElementById('login-screen').classList.add('hidden'); |
| document.getElementById('admin-panel').classList.remove('hidden'); |
| } |
| |
| function hideAdminPanel() { |
| document.getElementById('admin-panel').classList.add('hidden'); |
| document.getElementById('login-screen').classList.remove('hidden'); |
| } |
| |
| |
| let currentCode = null; |
| let expiryInterval = null; |
| |
| function generateCode() { |
| const username = document.getElementById('admin-username').value; |
| const password = document.getElementById('admin-password').value; |
| |
| if (!username || !password) { |
| alert('Please enter admin credentials'); |
| return; |
| } |
| |
| |
| |
| const code = Math.floor(100000 + Math.random() * 900000); |
| currentCode = code; |
| document.getElementById('generated-code').value = code; |
| |
| |
| const recentCodesDiv = document.getElementById('recent-codes'); |
| const codeElement = document.createElement('div'); |
| codeElement.className = 'py-1 border-b border-gray-200'; |
| codeElement.innerHTML = ` |
| <span class="font-mono">${code}</span> |
| <span class="text-gray-500 text-xs ml-2">${new Date().toLocaleTimeString()}</span> |
| `; |
| recentCodesDiv.prepend(codeElement); |
| |
| |
| let minutes = 4; |
| let seconds = 59; |
| document.getElementById('code-expiry').textContent = '5:00'; |
| |
| if (expiryInterval) clearInterval(expiryInterval); |
| |
| expiryInterval = setInterval(() => { |
| if (seconds === 0) { |
| if (minutes === 0) { |
| clearInterval(expiryInterval); |
| document.getElementById('code-expiry').textContent = 'Expired'; |
| currentCode = null; |
| return; |
| } |
| minutes--; |
| seconds = 59; |
| } else { |
| seconds--; |
| } |
| |
| const formattedSeconds = seconds < 10 ? `0${seconds}` : seconds; |
| document.getElementById('code-expiry').textContent = `${minutes}:${formattedSeconds}`; |
| }, 1000); |
| } |
| |
| function copyCode() { |
| if (!currentCode) { |
| alert('No code generated yet'); |
| return; |
| } |
| |
| navigator.clipboard.writeText(currentCode.toString()) |
| .then(() => alert('Code copied to clipboard')) |
| .catch(() => alert('Failed to copy code')); |
| } |
| |
| |
| function login() { |
| const code = document.getElementById('code').value; |
| |
| if (code) { |
| |
| document.getElementById('login-screen').classList.add('hidden'); |
| document.getElementById('app-interface').classList.remove('hidden'); |
| } else { |
| alert('Please enter both phone number and verification code'); |
| } |
| } |
| |
| |
| function showTab(tabName) { |
| if (tabName === 'posts') { |
| document.getElementById('posts-tab').classList.remove('hidden'); |
| document.getElementById('messages-tab').classList.add('hidden'); |
| |
| document.querySelectorAll('.flex.border-b button').forEach(btn => { |
| if (btn.textContent.includes('Posts')) { |
| btn.classList.add('text-blue-600', 'border-blue-600'); |
| btn.classList.remove('text-gray-500'); |
| } else { |
| btn.classList.remove('text-blue-600', 'border-blue-600'); |
| btn.classList.add('text-gray-500'); |
| } |
| }); |
| } else { |
| document.getElementById('posts-tab').classList.add('hidden'); |
| document.getElementById('messages-tab').classList.remove('hidden'); |
| |
| document.querySelectorAll('.flex.border-b button').forEach(btn => { |
| if (btn.textContent.includes('Messages')) { |
| btn.classList.add('text-blue-600', 'border-blue-600'); |
| btn.classList.remove('text-gray-500'); |
| } else { |
| btn.classList.remove('text-blue-600', 'border-blue-600'); |
| btn.classList.add('text-gray-500'); |
| } |
| }); |
| } |
| } |
| |
| |
| function showKotlinCode() { |
| document.getElementById('kotlin-code').classList.remove('hidden'); |
| } |
| |
| function hideKotlinCode() { |
| document.getElementById('kotlin-code').classList.add('hidden'); |
| } |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=ayham909/https-huggingface-co-organizations-towhed" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |