# راهنمای اتصال اپلیکیشن Android به SignalR برای Face Embedding ## 1. افزودن کتابخانه SignalR به پروژه Android در فایل `build.gradle` (Module: app) خود، dependency زیر را اضافه کنید: ```gradle dependencies { // SignalR for Android implementation 'com.microsoft.signalr:signalr:7.0.0' // اگر از Kotlin استفاده می‌کنید: implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1' // برای JSON پردازش: implementation 'com.google.code.gson:gson:2.10.1' } ``` ## 2. اضافه کردن Permission در AndroidManifest.xml ```xml ``` ## 3. کد Java/Kotlin برای اتصال به SignalR ### نسخه Java: ```java import com.microsoft.signalr.HubConnection; import com.microsoft.signalr.HubConnectionBuilder; import com.microsoft.signalr.HubConnectionState; import com.google.gson.JsonObject; import android.util.Log; public class FaceEmbeddingSignalRClient { private static final String TAG = "FaceEmbeddingHub"; private HubConnection hubConnection; private String serverUrl = "http://YOUR_SERVER_IP:PORT/trackingFaceEmbeddingHub"; // آدرس سرور خود را وارد کنید private long workshopId; public FaceEmbeddingSignalRClient(long workshopId) { this.workshopId = workshopId; initializeSignalR(); } private void initializeSignalR() { // ایجاد اتصال SignalR hubConnection = HubConnectionBuilder .create(serverUrl) .build(); // دریافت رویداد ایجاد Embedding hubConnection.on("EmbeddingCreated", (data) -> { JsonObject jsonData = (JsonObject) data; long employeeId = jsonData.get("employeeId").getAsLong(); String employeeFullName = jsonData.get("employeeFullName").getAsString(); String timestamp = jsonData.get("timestamp").getAsString(); Log.d(TAG, "Embedding Created - Employee: " + employeeFullName + " (ID: " + employeeId + ")"); // اینجا می‌توانید داده‌های جدید را از سرور بگیرید یا UI را بروزرسانی کنید onEmbeddingCreated(employeeId, employeeFullName, timestamp); }, JsonObject.class); // دریافت رویداد حذف Embedding hubConnection.on("EmbeddingDeleted", (data) -> { JsonObject jsonData = (JsonObject) data; long employeeId = jsonData.get("employeeId").getAsLong(); String timestamp = jsonData.get("timestamp").getAsString(); Log.d(TAG, "Embedding Deleted - Employee ID: " + employeeId); onEmbeddingDeleted(employeeId, timestamp); }, JsonObject.class); // دریافت رویداد بهبود Embedding hubConnection.on("EmbeddingRefined", (data) -> { JsonObject jsonData = (JsonObject) data; long employeeId = jsonData.get("employeeId").getAsLong(); String timestamp = jsonData.get("timestamp").getAsString(); Log.d(TAG, "Embedding Refined - Employee ID: " + employeeId); onEmbeddingRefined(employeeId, timestamp); }, JsonObject.class); } public void connect() { if (hubConnection.getConnectionState() == HubConnectionState.DISCONNECTED) { hubConnection.start() .doOnComplete(() -> { Log.d(TAG, "Connected to SignalR Hub"); joinWorkshopGroup(); }) .doOnError(error -> { Log.e(TAG, "Error connecting to SignalR: " + error.getMessage()); }) .subscribe(); } } private void joinWorkshopGroup() { // عضویت در گروه مخصوص این کارگاه hubConnection.send("JoinWorkshopGroup", workshopId); Log.d(TAG, "Joined workshop group: " + workshopId); } public void disconnect() { if (hubConnection.getConnectionState() == HubConnectionState.CONNECTED) { // خروج از گروه hubConnection.send("LeaveWorkshopGroup", workshopId); hubConnection.stop(); Log.d(TAG, "Disconnected from SignalR Hub"); } } // این متدها را در Activity/Fragment خود override کنید protected void onEmbeddingCreated(long employeeId, String employeeFullName, String timestamp) { // اینجا UI را بروزرسانی کنید یا داده جدید را بگیرید } protected void onEmbeddingDeleted(long employeeId, String timestamp) { // اینجا UI را بروزرسانی کنید } protected void onEmbeddingRefined(long employeeId, String timestamp) { // اینجا UI را بروزرسانی کنید } } ``` ### نسخه Kotlin: ```kotlin import com.microsoft.signalr.HubConnection import com.microsoft.signalr.HubConnectionBuilder import com.microsoft.signalr.HubConnectionState import com.google.gson.JsonObject import android.util.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class FaceEmbeddingSignalRClient(private val workshopId: Long) { companion object { private const val TAG = "FaceEmbeddingHub" } private lateinit var hubConnection: HubConnection private val serverUrl = "http://YOUR_SERVER_IP:PORT/trackingFaceEmbeddingHub" // آدرس سرور خود را وارد کنید init { initializeSignalR() } private fun initializeSignalR() { hubConnection = HubConnectionBuilder .create(serverUrl) .build() // دریافت رویداد ایجاد Embedding hubConnection.on("EmbeddingCreated", { data: JsonObject -> val employeeId = data.get("employeeId").asLong val employeeFullName = data.get("employeeFullName").asString val timestamp = data.get("timestamp").asString Log.d(TAG, "Embedding Created - Employee: $employeeFullName (ID: $employeeId)") onEmbeddingCreated(employeeId, employeeFullName, timestamp) }, JsonObject::class.java) // دریافت رویداد حذف Embedding hubConnection.on("EmbeddingDeleted", { data: JsonObject -> val employeeId = data.get("employeeId").asLong val timestamp = data.get("timestamp").asString Log.d(TAG, "Embedding Deleted - Employee ID: $employeeId") onEmbeddingDeleted(employeeId, timestamp) }, JsonObject::class.java) // دریافت رویداد بهبود Embedding hubConnection.on("EmbeddingRefined", { data: JsonObject -> val employeeId = data.get("employeeId").asLong val timestamp = data.get("timestamp").asString Log.d(TAG, "Embedding Refined - Employee ID: $employeeId") onEmbeddingRefined(employeeId, timestamp) }, JsonObject::class.java) } fun connect() { if (hubConnection.connectionState == HubConnectionState.DISCONNECTED) { CoroutineScope(Dispatchers.IO).launch { try { hubConnection.start().blockingAwait() Log.d(TAG, "Connected to SignalR Hub") joinWorkshopGroup() } catch (e: Exception) { Log.e(TAG, "Error connecting to SignalR: ${e.message}") } } } } private fun joinWorkshopGroup() { hubConnection.send("JoinWorkshopGroup", workshopId) Log.d(TAG, "Joined workshop group: $workshopId") } fun disconnect() { if (hubConnection.connectionState == HubConnectionState.CONNECTED) { hubConnection.send("LeaveWorkshopGroup", workshopId) hubConnection.stop() Log.d(TAG, "Disconnected from SignalR Hub") } } // این متدها را override کنید open fun onEmbeddingCreated(employeeId: Long, employeeFullName: String, timestamp: String) { // اینجا UI را بروزرسانی کنید یا داده جدید را بگیرید } open fun onEmbeddingDeleted(employeeId: Long, timestamp: String) { // اینجا UI را بروزرسانی کنید } open fun onEmbeddingRefined(employeeId: Long, timestamp: String) { // اینجا UI را بروزرسانی کنید } } ``` ## 4. استفاده در Activity یا Fragment ### مثال با Login و دریافت WorkshopId #### Java: ```java public class LoginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); Button btnLogin = findViewById(R.id.btnLogin); btnLogin.setOnClickListener(v -> performLogin()); } private void performLogin() { // فراخوانی API لاگین // فرض کنید response شامل workshopId است // مثال ساده (باید از Retrofit یا کتابخانه مشابه استفاده کنید): // LoginResponse response = apiService.login(username, password); // long workshopId = response.getWorkshopId(); long workshopId = 123; // این را از response دریافت کنید // ذخیره workshopId SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE); prefs.edit().putLong("workshopId", workshopId).apply(); // رفتن به صفحه اصلی Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); } } public class MainActivity extends AppCompatActivity { private FaceEmbeddingSignalRClient signalRClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // دریافت workshopId از SharedPreferences SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE); long workshopId = prefs.getLong("workshopId", 0); if (workshopId == 0) { // اگر workshopId وجود نداره، برگرد به صفحه لاگین Intent intent = new Intent(this, LoginActivity.class); startActivity(intent); finish(); return; } // ایجاد و اتصال SignalR signalRClient = new FaceEmbeddingSignalRClient(workshopId) { @Override protected void onEmbeddingCreated(long employeeId, String employeeFullName, String timestamp) { runOnUiThread(() -> { // بروزرسانی UI Toast.makeText(MainActivity.this, "Embedding ایجاد شد برای: " + employeeFullName, Toast.LENGTH_SHORT).show(); // دریافت داده‌های جدید از API refreshEmployeeList(); }); } @Override protected void onEmbeddingDeleted(long employeeId, String timestamp) { runOnUiThread(() -> { // بروزرسانی UI refreshEmployeeList(); }); } @Override protected void onEmbeddingRefined(long employeeId, String timestamp) { runOnUiThread(() -> { // بروزرسانی UI refreshEmployeeList(); }); } }; signalRClient.connect(); } @Override protected void onDestroy() { super.onDestroy(); if (signalRClient != null) { signalRClient.disconnect(); } } private void refreshEmployeeList() { // دریافت لیست جدید کارمندان از API } } ``` #### Kotlin: ```kotlin class LoginActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) val btnLogin = findViewById