diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..9211fb2 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,6 @@ +# These are supported funding model platforms + +ko_fi: saveriomorelli +liberapay: Sav22999 +custom: ["https://www.paypal.me/saveriomorelli"] +github: [Sav22999] diff --git a/.idea/.name b/.idea/.name index 8aac358..8985e8d 100644 --- a/.idea/.name +++ b/.idea/.name @@ -1 +1 @@ -Word of the Day \ No newline at end of file +list_item_word_history.xml \ No newline at end of file diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 0000000..d1bd91e --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,40 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index ae388c2..7b3006b 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,16 +4,16 @@ diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 7e340a7..fdf8d99 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 1174c62..6453479 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,3 +1,4 @@ + - + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..931b96c --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 0bd4844..304e4ea 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,13 @@ This app is developed by Saverio Morelli, using the Android Studio IDE. If you have any questions, please open an issue (you can add the label `question` there). Every day the app offers a new word to learn, so you will have a vast vocabulary. -You can read the definition of the word, its origin / etymology, its pronounciation / phonetics (RP-IPA). +You can read the definition of the word, its origin / etymology, its pronunciation / phonetics (RP-IPA). You can copy or share it as well! --------- - -The app contains advertisements, in this way you can support the developer indirectly. Either way, you can freely disable those in Settings. - ### Where download the app -[](https://play.google.com/store/apps/details?id=com.saverio.wordoftheday_en) +[](https://play.google.com/store/apps/details?id=com.saverio.wordoftheday_en) [](https://f-droid.org/it/packages/com.saverio.wordoftheday_en/) [](https://www.amazon.com/Word-day-Learn-word-every/dp/B09HPVKZD1/) You can download the app from the Google Play. @@ -30,11 +26,11 @@ You can download the app from the Google Play. If you like this project, leave a *Star* ⭐ to receive updates on your *GitHub dashboard*. -You can leave also a ⭐⭐⭐⭐⭐ *stars* review on Google Play it's very important for me. +You can leave also a ⭐⭐⭐⭐⭐ *stars* review on Google Play or Amazon AppStore it's very important for me. To support me, you can do a donation :smile: with **PayPal**, **LiberaPay** or **Ko-Fi**: -Donate using Liberapay [](https://paypal.me/pools/c/8yl6auiU6e) [](https://ko-fi.com/R5R31UQ8G) +Donate using Liberapay [](https://paypal.me/saveriomorelli) [](https://ko-fi.com/R5R31UQ8G) ### How contribute @@ -45,4 +41,4 @@ If you want to help to develop this app, you can open an `Issue` an send feedbac -![Generic badge](https://img.shields.io/badge/built%20in-Android%20Studio-green.svg) ![Generic badge](https://img.shields.io/badge/developed%20in-Kotlin-blue.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/Sav22999/sav-pdf-viewer-pro) [![Generic badge](https://img.shields.io/badge/developed%20by-Sav22999-lightgrey.svg)](https://saveriomorelli.com) \ No newline at end of file +![Generic badge](https://img.shields.io/badge/built%20in-Android%20Studio-green.svg) ![Generic badge](https://img.shields.io/badge/developed%20in-Kotlin-blue.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/Sav22999/sav-pdf-viewer-pro) [![Generic badge](https://img.shields.io/badge/developed%20by-Sav22999-lightgrey.svg)](https://saveriomorelli.com) diff --git a/app/build.gradle b/app/build.gradle index c0b2557..17c457f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,15 +1,17 @@ plugins { id 'com.android.application' id 'kotlin-android' + id 'kotlin-kapt' + id 'com.google.devtools.ksp' version '1.9.0-1.0.12' } android { - compileSdkVersion 33 + compileSdk 34 defaultConfig { applicationId 'com.saverio.wordoftheday_en' - minSdkVersion 16 - targetSdk 33 + minSdkVersion 21 + targetSdkVersion 34 versionCode 16 versionName '1.5' multiDexEnabled true @@ -40,30 +42,53 @@ android { signingConfig signingConfigs.debug } } + + compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + // Set both source and target compatibility to Java 17 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } + kotlinOptions { - jvmTarget = '1.8' + // Set Kotlin target to Java 17 + jvmTarget = "11" } + + // Enable the JVM toolchain to ensure consistent versioning + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) // Use 17 if you're downgrading Java + } + } + namespace 'com.saverio.wordoftheday_en' } - dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.2.1' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.core:core-ktx:1.13.1' + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'com.google.android.material:material:1.12.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.activity:activity:1.9.2' testImplementation 'junit:junit:4.13.1' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' - //implementation 'com.google.android.gms:play-services-ads:19.6.0' + // MultiDex support implementation 'com.android.support:multidex:1.0.3' -} \ No newline at end of file + + // Room dependencies + def room_version = '2.6.1' + implementation "androidx.room:room-runtime:$room_version" + implementation "androidx.room:room-ktx:$room_version" + ksp "androidx.room:room-compiler:2.5.0" + + // Optional for coroutines support +} + + diff --git a/app/src/androidTest/java/com/saverio/wordoftheday_en/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/saverio/wordoftheday_en/ExampleInstrumentedTest.kt deleted file mode 100644 index dc50492..0000000 --- a/app/src/androidTest/java/com/saverio/wordoftheday_en/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.saverio.wordoftheday_en - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.saverio.wordoftheday_en", appContext.packageName) - } -} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cc7d922..bb331d3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,9 +1,10 @@ - + - + - - + android:usesCleartextTraffic="true" + tools:targetApi="m"> + + + android:exported="true"> @@ -29,8 +30,8 @@ - // Now a suspend function +} \ No newline at end of file diff --git a/app/src/main/java/com/saverio/wordoftheday_en/WordDatabase.kt b/app/src/main/java/com/saverio/wordoftheday_en/WordDatabase.kt new file mode 100644 index 0000000..1fe5bcb --- /dev/null +++ b/app/src/main/java/com/saverio/wordoftheday_en/WordDatabase.kt @@ -0,0 +1,29 @@ +package com.saverio.wordoftheday_en + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database(entities = [Word::class], version = 1, exportSchema = false) +abstract class WordDatabase : RoomDatabase() { + abstract fun wordDao(): WordDao + + companion object { + @Volatile + private var INSTANCE: WordDatabase? = null + + fun getDatabase(context: Context): WordDatabase { + return INSTANCE ?: synchronized(this) { + val instance = Room.databaseBuilder( + + context.applicationContext, + WordDatabase::class.java, + "word_database" + ).build() + INSTANCE = instance + instance + } + } + } +} diff --git a/app/src/main/java/com/saverio/wordoftheday_en/WordHistoryActivity.kt b/app/src/main/java/com/saverio/wordoftheday_en/WordHistoryActivity.kt new file mode 100644 index 0000000..d56fb3a --- /dev/null +++ b/app/src/main/java/com/saverio/wordoftheday_en/WordHistoryActivity.kt @@ -0,0 +1,79 @@ +package com.saverio.wordoftheday_en + +import android.annotation.SuppressLint +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.Toast +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.core.view.WindowCompat +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class WordHistoryActivity : AppCompatActivity() { + private lateinit var wordHistoryAdapter: WordHistoryAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_word_history) + + val wordHistoryRecyclerView = findViewById(R.id.wordHistoryRecyclerView) + + // Load words using coroutines + CoroutineScope(Dispatchers.IO).launch { + try { + val words = loadWords() // Fetch words in the background + + // Toast to display fetched words + val wordsText = + words.joinToString(", ") { "${it.word}: ${it.definition}" } // Creating a string of words + Log.d("WordHistoryActivity", "Fetched words: $wordsText") // Log the words fetched + + withContext(Dispatchers.Main) { + // Now we're on the main thread, so we can update the UI + if (words.isNotEmpty()) { + wordHistoryAdapter = WordHistoryAdapter(words) + wordHistoryRecyclerView.adapter = wordHistoryAdapter + wordHistoryRecyclerView.layoutManager = + LinearLayoutManager(this@WordHistoryActivity) + wordHistoryAdapter.notifyDataSetChanged() // Notify the adapter of data changes + + // Show a Toast message with the words +// Toast.makeText(this@WordHistoryActivity, "Words loaded successfully: $wordsText", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText( + this@WordHistoryActivity, + "No words found!", + Toast.LENGTH_SHORT + ).show() + } + } + } catch (e: Exception) { + // Handle the exception (e.g., log it) + withContext(Dispatchers.Main) { + Toast.makeText( + this@WordHistoryActivity, + "Error loading words: ${e.message}", + Toast.LENGTH_SHORT + ).show() + } + } + } + } + + private suspend fun loadWords(): List { + val wordDao = WordDatabase.getDatabase(this).wordDao() + return wordDao.getAllWords() // This is now a suspend call + } + + fun backButton(view: android.view.View) { + finish() + } + +} diff --git a/app/src/main/java/com/saverio/wordoftheday_en/WordHistoryAdapter.kt b/app/src/main/java/com/saverio/wordoftheday_en/WordHistoryAdapter.kt new file mode 100644 index 0000000..ce31cae --- /dev/null +++ b/app/src/main/java/com/saverio/wordoftheday_en/WordHistoryAdapter.kt @@ -0,0 +1,31 @@ +package com.saverio.wordoftheday_en +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView + +class WordHistoryAdapter(private val words: List) : RecyclerView.Adapter() { + + class WordViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val wordView: TextView = itemView.findViewById(R.id.wordView) + val wordMeaningView: TextView = itemView.findViewById(R.id.wordMeaningView) + val wordDateView: TextView = itemView.findViewById(R.id.wordDateView) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordViewHolder { + val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item_word_history, parent, false) + return WordViewHolder(view) + } + + override fun onBindViewHolder(holder: WordViewHolder, position: Int) { + val word = words[position] + holder.wordDateView.text = word.date // Assuming `date` holds the date + holder.wordView.text = word.word // Assuming `word` has a `word` property + holder.wordMeaningView.text = word.definition // Assuming `definition` holds the meaning + } + + override fun getItemCount(): Int { + return words.size + } +} diff --git a/app/src/main/res/drawable/ic_history.xml b/app/src/main/res/drawable/ic_history.xml new file mode 100644 index 0000000..cc29a52 --- /dev/null +++ b/app/src/main/res/drawable/ic_history.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index c8f7823..0e6fe66 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -303,11 +303,12 @@ android:id="@+id/wordElement" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:elevation="0dp" android:paddingLeft="10sp" android:paddingTop="15sp" android:paddingRight="10sp" android:textSize="50sp" - android:elevation="0dp" app:flow_horizontalAlign="start" app:flow_verticalAlign="center" app:layout_constraintEnd_toEndOf="parent" @@ -317,8 +318,8 @@ + + + + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_word_history.xml b/app/src/main/res/layout/list_item_word_history.xml new file mode 100644 index 0000000..5270c72 --- /dev/null +++ b/app/src/main/res/layout/list_item_word_history.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2cd467b..a78c2d2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,6 +5,7 @@ ca-app-pub-4441008333572114/5206717736 Settings + Words learnt Definition Etymology diff --git a/app/src/test/java/com/saverio/wordoftheday_en/ExampleUnitTest.kt b/app/src/test/java/com/saverio/wordoftheday_en/ExampleUnitTest.kt deleted file mode 100644 index 70c0def..0000000 --- a/app/src/test/java/com/saverio/wordoftheday_en/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.saverio.wordoftheday_en - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff --git a/build.gradle b/build.gradle index ce8b47f..867a61f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,14 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - ext.kotlin_version = '1.6.21' +buildscript { ext { + agp_version = '8.7.0' +} + ext.kotlin_version = '1.9.10' // or whatever the latest version is repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.1.3' + classpath "com.android.tools.build:gradle:$agp_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index da1db5f..d4ec84b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ +#Sat Oct 12 14:23:15 CEST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +kapt.jvmArgs=--add-exports\=jdk.compiler/com.sun.tools.javac.main\=ALL-UNNAMED zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/images/amazonAppStoreBadge.png b/images/amazonAppStoreBadge.png new file mode 100644 index 0000000..bf66f96 Binary files /dev/null and b/images/amazonAppStoreBadge.png differ diff --git a/images/fDroidBadge.png b/images/fDroidBadge.png new file mode 100644 index 0000000..afa603c Binary files /dev/null and b/images/fDroidBadge.png differ