القائمة الرئيسية

الصفحات

كيفية برمجة تطبيق لتحويل النص إلى كلام على اندرويد ستوديو Kotlin | Java

PreferenceFragmentCompat, SharedPreferences, PreferenceScreen, ListPreference, EditTextPreference، strings.xml, values-ar, values-en, Locale، RecyclerView, Adapter, ViewHolder, LinearLayoutManager, RoomDatabase, Dao, Entity، getAvailableLanguages(), ArrayAdapter, AlertDialog، setSpeechRate(), setPitch(), SeekBar, AlertDialog، Google Play Console, نشر تطبيقات أندرويد, ملف APK/AAB, وصف التطبيق, لقطات شاشة، Intent ACTION_SEND, EXTRA_TEXT, startActivity()، حفظ الملفات, Internal Storage, FileOutputStream, Context.MODE_PRIVATE، Text-to-Speech, TTS engine, OnInitListener, speak(), setLanguage()، Android Studio, مشروع جديد, إنشاء تطبيق أندرويد، Android Studio, تحويل النص إلى كلام, TTS (Text-to-Speech), برمجة تطبيقات أندرويد, واجهة مستخدم أندرويد, حفظ النص, مشاركة التطبيق, تصميم تطبيقات احترافية, تجربة مستخدم, تطوير تطبيقات أندرويد، كيفية برمجة تطبيق لتحويل النص إلى كلام على اندرويد ستوديو Kotlin | Java، Android Studio, تحويل النص إلى كلام, TTS (Text-to-Speech), SharedPreferences, How to code a text-to-speech app on Android Studio using Kotlin | Java، كيفية برمجة تطبيق لتحويل النص إلى كلام على اندرويد ستوديو Kotlin | Java، How to code a text-to-speech app on Android Studio using Kotlin | Java، برمجة تطبيق لتحويل النص إلى كلام، برمجة تطبيق لتحويل النص إلى كلام باستخدام اندرويد ستوديو، برمجة، تطبيق لتحويل النص إلى كلام باستخدام اندرويد ستوديو، إنشاء تطبيق احترافي لتحويل النص إلى كلام، Android Studio، دليل شامل لإنشاء تطبيق احترافي لتحويل النص إلى كلام على أندرويد،





كيفية برمجة تطبيق لتحويل النص إلى كلام على اندرويد ستوديو Kotlin | Java



في عالم اليوم الرقمي السريع، أصبحت تطبيقات تحويل النص إلى كلام 
أدوات لا غنى عنها للعديد من المستخدمين، سواء لأغراض تسهيل الوصول،
 أو زيادة الإنتاجية، أو حتى الاستمتاع بتجربة استماع مريحة للمحتوى المكتوب. 
يهدف هذا المقال إلى تزويدك بخطوات مفصلة وأكواد عملية لإنشاء تطبيق
 أندرويد احترافي يقوم بتحويل النص إلى كلام، مع التركيز على الجودة وسهولة الاستخدام.


خطوات برمجة تطبيق لتحويل النص إلى كلام على اندرويد ستوديو Kotlin | Java


1. إنشاء مشروع جديد في Android Studio :

من خلال واجهة Android Studio. ابدأ بفتح Android Studio واختر
 "Start a new Android Studio project". حدد "Empty Activity" 
واختر اسم التطبيق واللغة (Java أو Kotlin) وموقع الحفظ.

2. تصميم واجهة المستخدم (UI) :

الكلمات المفتاحية: واجهة مستخدم أندرويد, تصميم UI, XML, EditText, Button.
الكود (ملف activity_main.xml) :




XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="top|start"
        android:hint="@string/enter_text"
        android:inputType="textMultiLine" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">

        <Button
            android:id="@+id/speakButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/speak"
            android:layout_marginEnd="8dp"/>

        <Button
            android:id="@+id/saveButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/save"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"/>

        <Button
            android:id="@+id/shareButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/share"
            android:layout_marginStart="8dp"/>

    </LinearLayout>

</LinearLayout>


--

* الكلمات المفتاحية للموارد (ملف strings.xml) :
XML

<resources>
    <string name="app_name">TextToSpeechApp</string>
    <string name="enter_text">أدخل النص هنا...</string>
    <string name="speak">تحدث</string>
    <string name="save">حفظ</string>
    <string name="share">مشاركة</string>
    <string name="text_saved">تم حفظ النص بنجاح</string>
    <string name="error_saving">حدث خطأ أثناء الحفظ</string>
</resources>
--

3. برمجة وظيفة تحويل النص إلى كلام (TTS):

قي  (ملف MainActivity.java أو MainActivity.kt):
** لغة Java :




Java

package com.example.texttospeechapp;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.util.Locale;

public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {

    private TextToSpeech mTTS;
    private EditText mEditText;
    private Button mSpeakButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEditText = findViewById(R.id.editText);
        mSpeakButton = findViewById(R.id.speakButton);
        Button saveButton = findViewById(R.id.saveButton);
        Button shareButton = findViewById(R.id.shareButton);

        mTTS = new TextToSpeech(this, this);

        mSpeakButton.setOnClickListener(v -> {
            String text = mEditText.getText().toString();
            if (text != null && !text.isEmpty()) {
                mTTS.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
            }
        });

        // سيتم إضافة أكواد حفظ ومشاركة النص لاحقاً
    }

    @Override
    public void onInit(int status) {
        if (status == TextToSpeech.SUCCESS) {
            int result = mTTS.setLanguage(Locale.getDefault());

            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Toast.makeText(this, "اللغة غير مدعومة", Toast.LENGTH_SHORT).show();
            } else {
                mSpeakButton.setEnabled(true);
            }
        } else {
            Toast.makeText(this, "فشل تهيئة محرك تحويل النص إلى كلام", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onDestroy() {
        if (mTTS != null) {
            mTTS.stop();
            mTTS.shutdown();
        }
        super.onDestroy();
    }
}


--

** لغة Kotlin :




Kotlin

package com.example.texttospeechapp

import android.os.Bundle
import android.speech.tts.TextToSpeech
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import java.util.Locale

class MainActivity : AppCompatActivity(), TextToSpeech.OnInitListener {

    private var mTTS: TextToSpeech? = null
    private lateinit var mEditText: EditText
    private lateinit var mSpeakButton: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mEditText = findViewById(R.id.editText)
        mSpeakButton = findViewById(R.id.speakButton)
        val saveButton: Button = findViewById(R.id.saveButton)
        val shareButton: Button = findViewById(R.id.shareButton)

        mTTS = TextToSpeech(this, this)

        mSpeakButton.setOnClickListener {
            val text = mEditText.text.toString()
            if (!text.isNullOrEmpty()) {
                mTTS?.speak(text, TextToSpeech.QUEUE_FLUSH, null, null)
            }
        }

        // سيتم إضافة أكواد حفظ ومشاركة النص لاحقاً
    }

    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
            val result = mTTS?.setLanguage(Locale.getDefault())

            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Toast.makeText(this, "اللغة غير مدعومة", Toast.LENGTH_SHORT).show()
            } else {
                mSpeakButton.isEnabled = true
            }
        } else {
            Toast.makeText(this, "فشل تهيئة محرك تحويل النص إلى كلام", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onDestroy() {
        if (mTTS != null) {
            mTTS?.stop()
            mTTS?.shutdown()
        }
        super.onDestroy()
    }
}


--

4. برمجة وظيفة حفظ النص :

الكود (إضافة داخل onCreate في MainActivity.java أو MainActivity.kt):




** لغة Java :
Java

        saveButton.setOnClickListener(v -> {
            String textToSave = mEditText.getText().toString();
            if (!textToSave.isEmpty()) {
                try {
                    java.io.FileOutputStream fos = openFileOutput("saved_text.txt", MODE_PRIVATE);
                    fos.write(textToSave.getBytes());
                    fos.close();
                    Toast.makeText(this, R.string.text_saved, Toast.LENGTH_SHORT).show();
                } catch (java.io.IOException e) {
                    e.printStackTrace();
                    Toast.makeText(this, R.string.error_saving, Toast.LENGTH_SHORT).show();
                }
            }
        });
--

** لغة Kotlin :
Kotlin

        saveButton.setOnClickListener {
            val textToSave = mEditText.text.toString()
            if (!textToSave.isEmpty()) {
                try {
                    val fos = openFileOutput("saved_text.txt", MODE_PRIVATE)
                    fos.write(textToSave.toByteArray())
                    fos.close()
                    Toast.makeText(this, R.string.text_saved, Toast.LENGTH_SHORT).show()
                } catch (e: java.io.IOException) {
                    e.printStackTrace()
                    Toast.makeText(this, R.string.error_saving, Toast.LENGTH_SHORT).show()
                }
            }
        }
--

5. برمجة وظيفة مشاركة النص :

(إضافة داخل onCreate في MainActivity.java أو MainActivity.kt) :
** لغة Java :
Java

        shareButton.setOnClickListener(v -> {
            String textToShare = mEditText.getText().toString();
            if (!textToShare.isEmpty()) {
                Intent shareIntent = new Intent(Intent.ACTION_SEND);
                shareIntent.setType("text/plain");
                shareIntent.putExtra(Intent.EXTRA_TEXT, textToShare);
                startActivity(Intent.createChooser(shareIntent, "مشاركة النص عبر..."));
            }
        });
--

** لغة Kotlin :
Kotlin

        shareButton.setOnClickListener {
            val textToShare = mEditText.text.toString()
            if (!textToShare.isEmpty()) {
                val shareIntent = Intent(Intent.ACTION_SEND)
                shareIntent.type = "text/plain"
                shareIntent.putExtra(Intent.EXTRA_TEXT, textToShare)
                startActivity(Intent.createChooser(shareIntent, "مشاركة النص عبر..."))
            }
        }
--

6. جعل التطبيق احترافياً - إضافات وميزات متقدمة :


1. خيارات صوت متقدمة: تغيير سرعة ونبرة الصوت

(إضافة دالة لعرض خيارات الصوت في MainActivity.java أو MainActivity.kt):
** لغة Java :




Java

    private void showSpeechSettings() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("إعدادات الصوت");

        View view = getLayoutInflater().inflate(R.layout.dialog_speech_settings, null);
        SeekBar speedSeekBar = view.findViewById(R.id.speedSeekBar);
        SeekBar pitchSeekBar = view.findViewById(R.id.pitchSeekBar);
        TextView speedValue = view.findViewById(R.id.speedValue);
        TextView pitchValue = view.findViewById(R.id.pitchValue);

        speedSeekBar.setProgress(50); // قيمة افتراضية للسرعة (0.0 - 1.0)
        pitchSeekBar.setProgress(50); // قيمة افتراضية للنبرة (0.0 - 2.0)

        speedSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float speed = (float) progress / 50.0f;
                mTTS.setSpeechRate(speed);
                speedValue.setText(String.format("%.2f", speed));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                // لا يلزم فعل شيء هنا
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                // لا يلزم فعل شيء هنا
            }
        });

        pitchSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float pitch = (float) progress / 50.0f;
                mTTS.setPitch(pitch);
                pitchValue.setText(String.format("%.2f", pitch));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                // لا يلزم فعل شيء هنا
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                // لا يلزم فعل شيء هنا
            }
        });

        builder.setView(view)
                .setPositiveButton("موافق", (dialog, which) -> {
                    // تم تطبيق الإعدادات عند الضغط على موافق
                })
                .setNegativeButton("إلغاء", (dialog, which) -> {
                    dialog.cancel();
                })
                .show();
    }


--

** لغة Kotlin :




Kotlin

    private fun showSpeechSettings() {
        val builder = AlertDialog.Builder(this)
        builder.setTitle("إعدادات الصوت")

        val view = layoutInflater.inflate(R.layout.dialog_speech_settings, null)
        val speedSeekBar = view.findViewById<SeekBar>(R.id.speedSeekBar)
        val pitchSeekBar = view.findViewById<SeekBar>(R.id.pitchSeekBar)
        val speedValue = view.findViewById<TextView>(R.id.speedValue)
        val pitchValue = view.findViewById<TextView>(R.id.pitchValue)

        speedSeekBar.progress = 50 // قيمة افتراضية للسرعة (0.0 - 1.0)
        pitchSeekBar.progress = 50 // قيمة افتراضية للنبرة (0.0 - 2.0)

        speedSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                val speed = progress / 50.0f
                mTTS?.setSpeechRate(speed)
                speedValue.text = String.format("%.2f", speed)
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
                // لا يلزم فعل شيء هنا
            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
                // لا يلزم فعل شيء هنا
            }
        })

        pitchSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                val pitch = progress / 50.0f
                mTTS?.setPitch(pitch)
                pitchValue.text = String.format("%.2f", pitch)
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
                // لا يلزم فعل شيء هنا
            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
                // لا يلزم فعل شيء هنا
            }
        })

        builder.setView(view)
            .setPositiveButton("موافق") { dialog, which ->
                // تم تطبيق الإعدادات عند الضغط على موافق
            }
            .setNegativeButton("إلغاء") { dialog, which ->
                dialog.cancel()
            }
            .show()
    }


--

* (ملف dialog_speech_settings.xml) :




XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="السرعة:"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center_vertical">

        <SeekBar
            android:id="@+id/speedSeekBar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:max="100" />

        <TextView
            android:id="@+id/speedValue"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="1.00" />

    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="النبرة:"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center_vertical">

        <SeekBar
            android:id="@+id/pitchSeekBar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:max="200" />

        <TextView
            android:id="@+id/pitchValue"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="1.00" />

    </LinearLayout>

</LinearLayout>


--

* لاستدعاء هذه الدالة عند الضغط على زر في واجهة المستخدم :
** لغة Java :
Java

        Button speechSettingsButton = findViewById(R.id.speechSettingsButton); // افترض وجود زر بهذا المعرف
        speechSettingsButton.setOnClickListener(v -> showSpeechSettings());
--

** لغة Kotlin :
Kotlin

        val speechSettingsButton: Button = findViewById(R.id.speechSettingsButton) // افترض وجود زر بهذا المعرف
        speechSettingsButton.setOnClickListener { showSpeechSettings() }
--

2. خيارات صوت متقدمة: عرض قائمة باللغات المتاحة

الكود (إضافة دالة لعرض قائمة اللغات في MainActivity.java أو MainActivity.kt):
** لغة Java :




Java

    private void showLanguageSelection() {
        Set<Locale> availableLanguages = mTTS.getAvailableLanguages();
        List<String> languageNames = new ArrayList<>();
        List<Locale> languageLocales = new ArrayList<>();

        for (Locale locale : availableLanguages) {
            languageNames.add(locale.getDisplayLanguage(Locale.getDefault()));
            languageLocales.add(locale);
        }

        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, languageNames);

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("اختر اللغة");
        builder.setAdapter(adapter, (dialog, which) -> {
            Locale selectedLocale = languageLocales.get(which);
            int result = mTTS.setLanguage(selectedLocale);
            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Toast.makeText(this, "هذه اللغة غير مدعومة", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "تم تغيير اللغة إلى " + selectedLocale.getDisplayLanguage(Locale.getDefault()), Toast.LENGTH_SHORT).show();
            }
        });
        builder.show();
    }


--

** لغة Kotlin :




Kotlin

    private fun showLanguageSelection() {
        val availableLanguages = mTTS?.availableLanguages
        val languageNames = mutableListOf<String>()
        val languageLocales = mutableListOf<Locale>()

        availableLanguages?.forEach { locale ->
            languageNames.add(locale.getDisplayLanguage(Locale.getDefault()))
            languageLocales.add(locale)
        }

        val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, languageNames)

        val builder = AlertDialog.Builder(this)
        builder.setTitle("اختر اللغة")
        builder.setAdapter(adapter) { dialog, which ->
            val selectedLocale = languageLocales[which]
            val result = mTTS?.setLanguage(selectedLocale)
            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Toast.makeText(this, "هذه اللغة غير مدعومة", Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this, "تم تغيير اللغة إلى ${selectedLocale.getDisplayLanguage(Locale.getDefault())}", Toast.LENGTH_SHORT).show()
            }
        }
        builder.show()
    }


--

* لاستدعاء هذه الدالة عند الضغط على زر في واجهة المستخدم :




* لغة Java :
Java

        Button languageButton = findViewById(R.id.languageButton); // افترض وجود زر بهذا المعرف
        languageButton.setOnClickListener(v -> showLanguageSelection());

** لغة Kotlin :
Kotlin

        val languageButton: Button = findViewById(R.id.languageButton) // افترض وجود زر بهذا المعرف
        languageButton.setOnClickListener { showLanguageSelection() }
--

3. إدارة النصوص المحفوظة: إنشاء شاشة لعرض قائمة بالنصوص المحفوظة 
(باستخدام RecyclerView و Room)

أ. إنشاء كيان (Entity) لتمثيل النص المحفوظ (SavedText.java أو SavedText.kt):
** لغة Java :

import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity(tableName = "saved_texts")
public class SavedText {
    @PrimaryKey(autoGenerate = true)
    private int id;

    private String text;
    private long timestamp;

    public SavedText(String text, long timestamp) {
        this.text = text;
        this.timestamp = timestamp;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public long getTimestamp() {
        return timestamp;
    }
}


--

** لغة Kotlin :

import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "saved_texts")
data class SavedText(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val text: String,
    val timestamp: Long
)
--

ب. إنشاء واجهة الوصول إلى البيانات (DAO) 
(SavedTextDao.java أو SavedTextDao.kt) :
** لغة Java :

import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
@Dao
public interface SavedTextDao {
    @Query("SELECT * FROM saved_texts ORDER BY timestamp DESC")
    List<SavedText> getAll();
    @Insert
    void insert(SavedText savedText);
    @Delete
    void delete(SavedText savedText);
}
--

** لغة Kotlin :

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
@Dao
interface SavedTextDao {
    @Query("SELECT * FROM saved_texts ORDER BY timestamp DESC")
    fun getAll(): List<SavedText>
    @Insert
    fun insert(savedText: SavedText)
    @Delete
    fun delete(savedText: SavedText)
}
--

ج. إنشاء قاعدة بيانات Room (AppDatabase.java أو AppDatabase.kt):
** لغة Java

import androidx.room.Database;
import androidx.room.RoomDatabase;

@Database(entities = {SavedText.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract SavedTextDao savedTextDao();

    private static volatile AppDatabase INSTANCE;

    public static AppDatabase getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = androidx.room.Room.databaseBuilder(context.getApplicationContext(),
                                    AppDatabase.class, "saved_texts_database")
                            .build();
                }
            }
        }
        return INSTANCE;
    }
}

--

** لغة Kotlin :

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

@Database(entities = [SavedText::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun savedTextDao(): SavedTextDao

    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "saved_texts_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

--

د. إنشاء محول (RecyclerView.Adapter) لعرض النصوص المحفوظة
 (SavedTextAdapter.java أو SavedTextAdapter.kt) :
** لغة Java :

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.text.DateFormat;
import java.util.List;
import java.util.Locale;

public class SavedTextAdapter extends RecyclerView.Adapter<SavedTextAdapter.SavedTextViewHolder> {

    private List<SavedText> savedTextList;
    private OnItemClickListener listener;

    public SavedTextAdapter(List<SavedText> savedTextList, OnItemClickListener listener) {
        this.savedTextList = savedTextList;
        this.listener = listener;
    }

    @NonNull
    @Override
    public SavedTextViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_saved_text, parent, false);
        return new SavedTextViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull SavedTextViewHolder holder, int position) {
        SavedText currentText = savedTextList.get(position);
        holder.textViewText.setText(currentText.getText());
        String formattedDate = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT, Locale.getDefault()).format(currentText.getTimestamp());
        holder.textViewTimestamp.setText(formattedDate);

        holder.itemView.setOnClickListener(v -> {
            listener.onItemClick(currentText);
        });
    }

    @Override
    public int getItemCount() {
        return savedTextList.size();
    }

    public static class SavedTextViewHolder extends RecyclerView.ViewHolder {
        public TextView textViewText;
        public TextView textViewTimestamp;

        public SavedTextViewHolder(@NonNull View itemView) {
            super(itemView);
            textViewText = itemView.findViewById(R.id.textViewSavedText);
            textViewTimestamp = itemView.findViewById(R.id.textViewTimestamp);
        }
    }

    public interface OnItemClickListener {
        void onItemClick(SavedText savedText);
    }

    public void setSavedTexts(List<SavedText> savedTexts) {
        this.savedTextList = savedTexts;
        notifyDataSetChanged();
    }
}

--

** لغة Kotlin :

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import java.text.DateFormat
import java.util.Date
import java.util.Locale

class SavedTextAdapter(
    private var savedTextList: List<SavedText>,
    private val listener: OnItemClickListener
) : RecyclerView.Adapter<SavedTextAdapter.SavedTextViewHolder>() {

    inner class SavedTextViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val textViewText: TextView = itemView.findViewById(R.id.textViewSavedText)
        val textViewTimestamp: TextView = itemView.findViewById(R.id.textViewTimestamp)

        init {
            itemView.setOnClickListener {
                val position = adapterPosition
                if (position != RecyclerView.NO_POSITION) {
                    listener.onItemClick(savedTextList[position])
                }
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SavedTextViewHolder {
        val itemView = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_saved_text, parent, false)
        return SavedTextViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: SavedTextViewHolder, position: Int) {
        val currentText = savedTextList[position]
        holder.textViewText.text = currentText.text
        val formattedDate = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT, Locale.getDefault()).format(Date(currentText.timestamp))
        holder.textViewTimestamp.text = formattedDate
    }

    override fun getItemCount(): Int {
        return savedTextList.size
    }

    fun setSavedTexts(savedTexts: List<SavedText>) {
        this.savedTextList = savedTexts
        notifyDataSetChanged()
    }

    interface OnItemClickListener {
        fun onItemClick(savedText: SavedText)
    }
}

--

* (ملف item_saved_text.xml لتصميم شكل كل عنصر في القائمة) :
XML




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/textViewSavedText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/textViewTimestamp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:textAppearance="?android:attr/textAppearanceSmall" />

</LinearLayout>


--

هـ. إنشاء شاشة لعرض النصوص المحفوظة 
(SavedTextsActivity.java أو SavedTextsActivity.kt) :
** لغة Java

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SavedTextsActivity extends AppCompatActivity implements SavedTextAdapter.OnItemClickListener {

    private RecyclerView recyclerView;
    private SavedTextAdapter adapter;
    private AppDatabase db;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_saved_texts);

        recyclerView = findViewById(R.id.recyclerViewSavedTexts);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        db = AppDatabase.getDatabase(getApplicationContext());

        ExecutorService executor = Executors.newSingleThreadExecutor();
        Handler handler = new Handler(Looper.getMainLooper());

        executor.execute(() -> {
            List<SavedText> savedTexts = db.savedTextDao().getAll();
            handler.post(() -> {
                adapter = new SavedTextAdapter(savedTexts, SavedTextsActivity.this);
                recyclerView.setAdapter(adapter);
            });
        });
    }

    @Override
    public void onItemClick(SavedText savedText) {
        // يمكنك هنا إضافة منطق لفتح النص المحدد أو حذفه
        Toast.makeText(this, "تم النقر على: " + savedText.getText(), Toast.LENGTH_SHORT).show();
        // مثال للحذف عند النقر:
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Handler handler = new Handler(Looper.getMainLooper());
        executor.execute(() -> {
            db.savedTextDao().delete(savedText);
            List<SavedText> updatedList = db.savedTextDao().getAll();
            handler.post(() -> {
                adapter.setSavedTexts(updatedList);
            });
        });
    }
}

--

** لغة Kotlin

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.util.concurrent.Executors

class SavedTextsActivity : AppCompatActivity(), SavedTextAdapter.OnItemClickListener {

    private lateinit var recyclerView: RecyclerView
    private lateinit var adapter: SavedTextAdapter
    private lateinit var db: AppDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_saved_texts)

        recyclerView = findViewById(R.id.recyclerViewSavedTexts)
        recyclerView.layoutManager = LinearLayoutManager(this)

        db = AppDatabase.getDatabase(applicationContext)

        val executor = Executors.newSingleThreadExecutor()
        val handler = Handler(Looper.getMainLooper())

        executor.execute {
            val savedTexts = db.savedTextDao().getAll()
            handler.post {
                adapter = SavedTextAdapter(savedTexts, this@SavedTextsActivity)
                recyclerView.adapter = adapter
            }
        }
    }

    override fun onItemClick(savedText: SavedText) {
        // يمكنك هنا إضافة منطق لفتح النص المحدد أو حذفه
        Toast.makeText(this, "تم النقر على: ${savedText.text}", Toast.LENGTH_SHORT).show()
        // مثال للحذف عند النقر:
        val executor = Executors.newSingleThreadExecutor()
        val handler = Handler(Looper.getMainLooper())
        executor.execute {
            db.savedTextDao().delete(savedText)
            val updatedList = db.savedTextDao().getAll()
            handler.post {
                adapter.setSavedTexts(updatedList)
            }
        }
    }
}

--

* (ملف activity_saved_texts.xml) :
XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recyclerViewSavedTexts"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
--

و. لتحديث كود الحفظ في MainActivity لإضافة الطابع الزمني :
** لغة Java:
Java

        saveButton.setOnClickListener(v -> {
            String textToSave = mEditText.getText().toString();
            if (!textToSave.isEmpty()) {
                ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.execute(() -> {
                    SavedText savedText = new SavedText(textToSave, System.currentTimeMillis());
                    db.savedTextDao().insert(savedText);
                    runOnUiThread(() -> Toast.makeText(MainActivity.this, R.string.text_saved, Toast.LENGTH_SHORT).show());
                });
            }
        });
--

* لغة Kotlin :
Kotlin

        saveButton.setOnClickListener {
            val textToSave = mEditText.text.toString()
            if (!textToSave.isEmpty()) {
                val executor = Executors.newSingleThreadExecutor()
                executor.execute {
                    val savedText = SavedText(text = textToSave, timestamp = System.currentTimeMillis())
                    db.savedTextDao().insert(savedText)
                    runOnUiThread { Toast.makeText(this@MainActivity, R.string.text_saved, Toast.LENGTH_SHORT).show() }
                }
            }
        }
--

ز. إضافة زر في واجهة MainActivity للانتقال إلى شاشة النصوص المحفوظة:
XML

        <Button
            android:id="@+id/viewSavedButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="المحفوظات"
            android:layout_marginStart="8dp"/>
--

ح. إضافة وظيفة الانتقال إلى شاشة النصوص المحفوظة في MainActivity:
** Java :
Java

        Button viewSavedButton = findViewById(R.id.viewSavedButton);
        viewSavedButton.setOnClickListener(v -> {
            Intent intent = new Intent(MainActivity.this, SavedTextsActivity.class);
            startActivity(intent);
        });
--

** لغة Kotlin :
Kotlin

        val viewSavedButton: Button = findViewById(R.id.viewSavedButton)
        viewSavedButton.setOnClickListener {
            val intent = Intent(this, SavedTextsActivity::class.java)
            startActivity(intent)
        }
--

4. دعم اللغات المتعددة

الخطوات :
- في مجلد res/values/، لديك بالفعل ملف strings.xml للغة الافتراضية (عادة الإنجليزية).
- لإضافة دعم للغة العربية، انقر بزر الفأرة الأيمن على مجلد values واختر New > Values Resource File.
- في نافذة "New Resource File"، أدخل strings في اسم الملف واختر Locale من قائمة "Qualifier".
- اختر ar (Arabic) وانقر OK. سيتم إنشاء مجلد جديد باسم values-ar يحتوي على ملف strings.xml.
- كرر هذه العملية لإضافة لغات أخرى (مثل values-en للغة الإنجليزية إذا لم يكن موجوداً).
- في كل ملف strings.xml، قم بتوفير ترجمة للقيم النصية المستخدمة في تطبيقك.




** مثال (res/values/strings.xml - الإنجليزية):
XML

<resources>
    <string name="app_name">TextToSpeechApp</string>
    <string name="enter_text">Enter text here...</string>
    <string name="speak">Speak</string>
    <string name="save">Save</string>
    <string name="share">Share</string>
    <string name="text_saved">Text saved successfully</string>
    <string name="error_saving">Error saving text</string>
    <string name="speech_settings">Speech Settings</string>
    <string name="language">Language</string>
    <string name="saved_texts">Saved Texts</string>
</resources>
--

* مثال (res/values-ar/strings.xml - العربية) :
XML

<resources>
    <string name="app_name">تطبيق تحويل النص إلى كلام</string>
    <string name="enter_text">أدخل النص هنا...</string>
    <string name="speak">تحدث</string>
    <string name="save">حفظ</string>
    <string name="share">مشاركة</string>
    <string name="text_saved">تم حفظ النص بنجاح</string>
    <string name="error_saving">حدث خطأ أثناء الحفظ</string>
    <string name="speech_settings">إعدادات الصوت</string>
    <string name="language">اللغة</string>
    <string name="saved_texts">النصوص المحفوظة</string>
</resources>
--

السماح للمستخدم باختيار لغة الإخراج الصوتي (تم تغطيته في الجزء الخاص بخيارات الصوت المتقدمة).

5. إعدادات التطبيق
* الخطوات :
إنشاء ملف XML للإعدادات (preferences.xml في مجلد res/xml/) :




XML

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory android:title="إعدادات الصوت">

        <ListPreference
            android:key="pref_language"
            android:title="لغة الإخراج"
            android:entries="@array/languages_array"
            android:entryValues="@array/languages_values"
            android:defaultValue="default"
            android:summary="اختر اللغة التي سيتم استخدامها لتحويل النص إلى كلام" />

        <EditTextPreference
            android:key="pref_speech_rate"
            android:title="سرعة الكلام الافتراضية"
            android:defaultValue="1.0"
            android:inputType="numberDecimal"
            android:summary="اضبط سرعة الكلام الافتراضية" />

    </PreferenceCategory>

</PreferenceScreen>


--

* إنشاء مصفوفات للغات في res/values/arrays.xml :
XML

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="languages_array">
        <item>افتراضي</item>
        <item>الإنجليزية</item>
        <item>العربية</item>
        </string-array>
    <string-array name="languages_values">
        <item>default</item>
        <item>en</item>
        <item>ar</item>
    </string-array>
</resources>
--

* إنشاء Fragment لعرض الإعدادات 
(SettingsFragment.java أو SettingsFragment.kt) :
Java

import android.os.Bundle;

import androidx.preference.PreferenceFragmentCompat;

public class SettingsFragment extends PreferenceFragmentCompat {
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.preferences, rootKey);
    }
}
--
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat

class SettingsFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.preferences, rootKey)
    }
}
--

* إنشاء Activity لاستضافة Fragment الإعدادات 
(SettingsActivity.java أو SettingsActivity.kt) :
** لغة Java

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;

import android.os.Bundle;

public class SettingsActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(android.R.id.content, new SettingsFragment())
                .commit();
    }
}
--

* لغة Kotlin

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentManager

class SettingsActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_settings)
        val fragmentManager: FragmentManager = supportFragmentManager
        fragmentManager.beginTransaction()
            .replace(android.R.id.content, SettingsFragment())
            .commit()
    }
}
--

* إنشاء تخطيط بسيط لـ SettingsActivity (activity_settings.xml) :
XML

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

* ربط الإعدادات بـ MainActivity :

لجعل تطبيقك يستخدم الإعدادات التي يختارها المستخدم، ستحتاج إلى قراءة 
قيم SharedPreferences في MainActivity وتطبيقها على 
محرك تحويل النص إلى كلام (TextToSpeech).

* (إضافة في MainActivity.java أو MainActivity.kt) :
** لغة Java :




Java

import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.speech.tts.TextToSpeech;
import android.widget.Button;

// ... باقي الأكواد ...

public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {

    private TextToSpeech mTTS;
    private EditText mEditText;
    private Button mSpeakButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEditText = findViewById(R.id.editText);
        mSpeakButton = findViewById(R.id.speakButton);
        Button saveButton = findViewById(R.id.saveButton);
        Button shareButton = findViewById(R.id.shareButton);
        Button settingsButton = findViewById(R.id.settingsButton); // افترض وجود زر للإعدادات

        mTTS = new TextToSpeech(this, this);

        settingsButton.setOnClickListener(v -> {
            Intent intent = new Intent(MainActivity.this, SettingsActivity.class);
            startActivity(intent);
        });

        mSpeakButton.setOnClickListener(v -> {
            String text = mEditText.getText().toString();
            if (text != null && !text.isEmpty()) {
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
                String languageCode = prefs.getString("pref_language", Locale.getDefault().getLanguage());
                float speechRate = Float.parseFloat(prefs.getString("pref_speech_rate", "1.0"));

                Locale localeToSpeak;
                if (languageCode.equals("en")) {
                    localeToSpeak = Locale.ENGLISH;
                } else if (languageCode.equals("ar")) {
                    localeToSpeak = new Locale("ar");
                } else {
                    localeToSpeak = Locale.getDefault();
                }

                int result = mTTS.setLanguage(localeToSpeak);
                if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                    Toast.makeText(this, "اللغة المحددة غير مدعومة", Toast.LENGTH_SHORT).show();
                } else {
                    mTTS.setSpeechRate(speechRate);
                    mTTS.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
                }
            }
        });

        // ... باقي أكواد حفظ ومشاركة النص ...
    }

    @Override
    public void onInit(int status) {
        if (status == TextToSpeech.SUCCESS) {
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
            String languageCode = prefs.getString("pref_language", Locale.getDefault().getLanguage());

            Locale localeOnInit;
            if (languageCode.equals("en")) {
                localeOnInit = Locale.ENGLISH;
            } else if (languageCode.equals("ar")) {
                localeOnInit = new Locale("ar");
            } else {
                localeOnInit = Locale.getDefault();
            }

            int result = mTTS.setLanguage(localeOnInit);

            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Toast.makeText(this, "اللغة الافتراضية غير مدعومة", Toast.LENGTH_SHORT).show();
            } else {
                mSpeakButton.setEnabled(true);
            }
        } else {
            Toast.makeText(this, "فشل تهيئة محرك تحويل النص إلى كلام", Toast.LENGTH_SHORT).show();
        }
    }

    // ... باقي أكواد onDestroy ...
}


--

** لغة Kotlin :




Kotlin

import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.preference.PreferenceManager
import android.speech.tts.TextToSpeech
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import java.util.Locale

class MainActivity : AppCompatActivity(), TextToSpeech.OnInitListener {

    private var mTTS: TextToSpeech? = null
    private lateinit var mEditText: EditText
    private lateinit var mSpeakButton: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mEditText = findViewById(R.id.editText)
        mSpeakButton = findViewById(R.id.speakButton)
        val saveButton: Button = findViewById(R.id.saveButton)
        val shareButton: Button = findViewById(R.id.shareButton)
        val settingsButton: Button = findViewById(R.id.settingsButton) // افترض وجود زر للإعدادات

        mTTS = TextToSpeech(this, this)

        settingsButton.setOnClickListener {
            val intent = Intent(this, SettingsActivity::class.java)
            startActivity(intent)
        }

        mSpeakButton.setOnClickListener {
            val text = mEditText.text.toString()
            if (!text.isNullOrEmpty()) {
                val prefs = PreferenceManager.getDefaultSharedPreferences(this)
                val languageCode = prefs.getString("pref_language", Locale.getDefault().language)
                val speechRate = prefs.getString("pref_speech_rate", "1.0")?.toFloat() ?: 1.0f

                val localeToSpeak = when (languageCode) {
                    "en" -> Locale.ENGLISH
                    "ar" -> Locale("ar")
                    else -> Locale.getDefault()
                }

                val result = mTTS?.setLanguage(localeToSpeak)
                if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                    Toast.makeText(this, "اللغة المحددة غير مدعومة", Toast.LENGTH_SHORT).show()
                } else {
                    mTTS?.speechRate = speechRate
                    mTTS?.speak(text, TextToSpeech.QUEUE_FLUSH, null, null)
                }
            }
        }

        // ... باقي أكواد حفظ ومشاركة النص ...
    }

    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
            val prefs = PreferenceManager.getDefaultSharedPreferences(this)
            val languageCode = prefs.getString("pref_language", Locale.getDefault().language)

            val localeOnInit = when (languageCode) {
                "en" -> Locale.ENGLISH
                "ar" -> Locale("ar")
                else -> Locale.getDefault()
            }

            val result = mTTS?.setLanguage(localeOnInit)

            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Toast.makeText(this, "اللغة الافتراضية غير مدعومة", Toast.LENGTH_SHORT).show()
            } else {
                mSpeakButton.isEnabled = true
            }
        } else {
            Toast.makeText(this, "فشل تهيئة محرك تحويل النص إلى كلام", Toast.LENGTH_SHORT).show()
        }
    }

    // ... باقي أكواد onDestroy ...
}


--

* تأكد من إضافة زر في تخطيط activity_main.xml للانتقال إلى شاشة الإعدادات :

    <Button
android:id="@+id/settingsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="الإعدادات"
android:layout_marginTop="16dp"/>
-- 

(يمكنك تعديل مكان هذا الزر وتصميمه حسب تخطيطك).
الآن، تم استكمال الجزء الخاص بإعدادات التطبيق مع الأكواد اللازمة لإنشاء شاشة 
الإعدادات وربطها بوظيفة تحويل النص إلى كلام في MainActivity.

7. نشر التطبيق :

* الخطوات :
- إنشاء حساب مطور على Google Play Console : يتطلب ذلك دفع رسوم تسجيل لمرة واحدة.
- إعداد قائمة التطبيق : قم بتوفير اسم التطبيق، ووصفاً مفصلاً، 
وفئة التطبيق، ومعلومات الاتصال، وسياسة الخصوصية.
- تحميل ملف APK أو AAB : قم بإنشاء ملف الإصدار من مشروعك في
 Android Studio (Build > Generate Signed Bundle / APK).
 يُفضل استخدام Android App Bundle (AAB) لتوفير حجم تنزيل أصغر للمستخدمين.
- توفير الأصول الرسومية : قم بتحميل أيقونة التطبيق، ولقطات شاشة تعرض وظائف التطبيق، وصور مميزة.
- تحديد التسعير والتوزيع : حدد ما إذا كان التطبيق مجانياً أو مدفوعاً، واختر
 البلدان التي ترغب في توفير التطبيق فيها.
- مراجعة ونشر : بعد ملء جميع المعلومات وتحميل الملفات المطلوبة، قم بمراجعة القائمة
 ثم انقر على "Go live" أو "نشر". قد تستغرق عملية المراجعة بضعة أيام.

* خاتمة :

باتباع هذه الخطوات وإضافة التحسينات المقترحة، يمكنك إنشاء تطبيق احترافي
 لتحويل النص إلى كلام يلبي احتياجات المستخدمين ويوفر تجربة استخدام ممتازة.
 تذكر أن التطوير المستمر والاستماع إلى ملاحظات المستخدمين
 يلعبان دوراً حاسماً في نجاح تطبيقك على المدى الطويل.



أنت الان في اول موضوع
جدول المحتويات