ayham909's picture
اضف امكانية متابعة الاخوة لرئية المنشورات - Initial Deployment
81c0e16 verified
<!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">
<!-- Login Screen -->
<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>
<!-- Admin Panel (Hidden by default) -->
<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> <!-- Spacer for alignment -->
</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">
<!-- Generated codes will appear here -->
</div>
</div>
</div>
</div>
</div>
<!-- Main App Interface (Hidden until login) -->
<div id="app-interface" class="hidden">
<!-- App Bar with Tabs -->
<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>
<!-- Content Area -->
<div class="chat-container pt-24 pb-16 overflow-y-auto">
<!-- Posts Tab -->
<div id="posts-tab" class="flex flex-col">
<!-- Posts Filter -->
<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>
<!-- Create Post -->
<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>
<!-- Sample Posts -->
<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>
<!-- Messages Tab (hidden by default) -->
<div id="messages-tab" class="hidden flex flex-col space-y-2 px-4">
<!-- Date divider -->
<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>
<!-- Received message -->
<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>
<!-- Sent message -->
<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>
<!-- Input Area -->
<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>
<!-- Floating action button -->
<div class="floating-button bg-blue-600 text-white hover:bg-blue-700">
<i class="fas fa-comment-medical"></i>
</div>
</div>
<!-- Kotlin Code Section (Hidden by default) -->
<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&lt;Message&gt;()
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&lt;Message&gt;) :
RecyclerView.Adapter&lt;MessageAdapter.MessageViewHolder&gt;() {
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>
<!-- View Code Button -->
<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>
// Show/hide admin panel
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');
}
// Admin functions
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;
}
// In a real app, verify admin credentials with backend here
const code = Math.floor(100000 + Math.random() * 900000);
currentCode = code;
document.getElementById('generated-code').value = code;
// Add to recent codes
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);
// Start countdown timer (5 minutes)
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'));
}
// Login function
function login() {
const code = document.getElementById('code').value;
if (code) {
// In a real app, you would verify with backend
document.getElementById('login-screen').classList.add('hidden');
document.getElementById('app-interface').classList.remove('hidden');
} else {
alert('Please enter both phone number and verification code');
}
}
// Tab switching
function showTab(tabName) {
if (tabName === 'posts') {
document.getElementById('posts-tab').classList.remove('hidden');
document.getElementById('messages-tab').classList.add('hidden');
// Update active tab styling
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');
// Update active tab styling
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');
}
});
}
}
// Show/hide Kotlin code
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>