Skip to content

Commit 0f60386

Browse files
author
Mihai-Cristian Condrea
committed
refactor: Updated UI for settings and removed ads
- Updated App Core to use BaseCoreManager. - Updated UI of settings to be more tablet friendly. - Updated the settings composables to use a shared list and detail view. - Added animations for settings detail view. - Removed unused SuppressLint annotations.
1 parent 86c1cc2 commit 0f60386

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1481
-1513
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
# Version 1.1.4:
1+
# Version 1.2.0:
22

3+
- **New**: Added navigation rail for tablets and landscape mode for better usability on larger screens.
4+
- **New**: Settings reorganized for clarity and better user experience on larger screens.
35
- **Minor**: Improved app performance and stability.
46
- **Minor**: Enhanced data management for a smoother user experience.
57

app/build.gradle.kts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ android {
1919
applicationId = "com.d4rk.androidtutorials"
2020
minSdk = 23
2121
targetSdk = 35
22-
versionCode = 107
23-
versionName = "1.1.4"
22+
versionCode = 108
23+
versionName = "1.2.0"
2424
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2525
@Suppress("UnstableApiUsage")
2626
androidResources.localeFilters += listOf(
@@ -106,8 +106,9 @@ android {
106106
}
107107

108108
dependencies {
109+
109110
// App Core
110-
implementation(dependencyNotation = "com.github.D4rK7355608:AppToolkit:0.0.24") {
111+
implementation(dependencyNotation = "com.github.D4rK7355608:AppToolkit:0.0.40") {
111112
isTransitive = true
112113
}
113114

@@ -121,13 +122,10 @@ dependencies {
121122
implementation(dependencyNotation = libs.firebase.perf)
122123

123124
// Google
124-
implementation(dependencyNotation = libs.play.services.ads)
125125
implementation(dependencyNotation = libs.billing)
126126
implementation(dependencyNotation = libs.app.update.ktx)
127127
implementation(dependencyNotation = libs.review.ktx)
128128
implementation(dependencyNotation = libs.generativeai)
129-
// TODO For lib:
130-
implementation("androidx.compose.material3:material3-adaptive-navigation-suite")
131129

132130
// KSP
133131
ksp(dependencyNotation = libs.androidx.room.compiler)

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,30 +84,14 @@
8484
</intent-filter>
8585
</activity>
8686

87-
<activity
88-
android:name=".ui.screens.settings.display.DisplaySettingsActivity"
89-
android:parentActivityName=".ui.screens.settings.SettingsActivity"
90-
android:windowSoftInputMode="adjustResize" />
91-
92-
<activity
93-
android:name=".ui.screens.settings.display.theme.ThemeSettingsActivity"
94-
android:parentActivityName=".ui.screens.settings.display.DisplaySettingsActivity"
95-
android:windowSoftInputMode="adjustResize" />
96-
97-
<activity
98-
android:name=".ui.screens.settings.advanced.AdvancedSettingsActivity"
99-
android:parentActivityName=".ui.screens.settings.SettingsActivity"
100-
android:windowSoftInputMode="adjustResize" />
10187

102-
<activity
103-
android:name=".ui.screens.settings.privacy.PrivacySettingsActivity"
88+
<activity android:name=".ui.screens.settings.general.GeneralSettingsActivity"
10489
android:parentActivityName=".ui.screens.settings.SettingsActivity"
10590
android:windowSoftInputMode="adjustResize" />
10691

10792
<activity
10893
android:name=".ui.screens.settings.privacy.permissions.PermissionsSettingsActivity"
10994
android:exported="true"
110-
android:parentActivityName=".ui.screens.settings.privacy.PrivacySettingsActivity"
11195
android:permission="android.permission.START_VIEW_PERMISSION_USAGE"
11296
android:windowSoftInputMode="adjustResize">
11397
<intent-filter>
@@ -118,19 +102,8 @@
118102
</intent-filter>
119103
</activity>
120104

121-
<activity
122-
android:name=".ui.screens.settings.privacy.usage.UsageAndDiagnosticsActivity"
123-
android:parentActivityName=".ui.screens.settings.privacy.PrivacySettingsActivity"
124-
android:windowSoftInputMode="adjustResize" />
125-
126105
<activity
127106
android:name=".ui.screens.settings.privacy.ads.AdsSettingsActivity"
128-
android:parentActivityName=".ui.screens.settings.privacy.PrivacySettingsActivity"
129-
android:windowSoftInputMode="adjustResize" />
130-
131-
<activity
132-
android:name=".ui.screens.settings.about.AboutSettingsActivity"
133-
android:parentActivityName=".ui.screens.settings.SettingsActivity"
134107
android:windowSoftInputMode="adjustResize" />
135108

136109
<activity

app/src/main/kotlin/com/d4rk/androidtutorials/data/core/AppCoreManager.kt

Lines changed: 52 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -4,155 +4,98 @@ package com.d4rk.androidtutorials.data.core
44

55
import android.annotation.SuppressLint
66
import android.app.Activity
7-
import android.app.Application
87
import android.database.sqlite.SQLiteException
98
import android.os.Bundle
109
import android.util.Log
1110
import androidx.lifecycle.Lifecycle
12-
import androidx.lifecycle.LifecycleObserver
1311
import androidx.lifecycle.OnLifecycleEvent
1412
import androidx.lifecycle.ProcessLifecycleOwner
15-
import androidx.multidex.MultiDexApplication
1613
import androidx.room.Room
1714
import androidx.room.migration.Migration
18-
import com.d4rk.android.libs.apptoolkit.data.client.KtorClient
15+
import com.d4rk.android.libs.apptoolkit.data.core.BaseCoreManager
16+
import com.d4rk.android.libs.apptoolkit.data.core.ads.AdsCoreManager
1917
import com.d4rk.android.libs.apptoolkit.utils.error.ErrorHandler
2018
import com.d4rk.android.libs.apptoolkit.utils.error.ErrorHandler.handleInitializationFailure
21-
import com.d4rk.androidtutorials.data.core.ads.AdsCoreManager
22-
import com.d4rk.androidtutorials.data.core.datastore.DataStoreCoreManager
2319
import com.d4rk.androidtutorials.data.database.AppDatabase
2420
import com.d4rk.androidtutorials.data.database.migrations.MIGRATION_1_2
2521
import com.d4rk.androidtutorials.data.database.migrations.MIGRATION_2_3
2622
import com.d4rk.androidtutorials.data.datastore.DataStore
23+
import com.d4rk.androidtutorials.utils.constants.ads.AdsConstants
2724
import com.d4rk.androidtutorials.utils.error.CrashlyticsErrorReporter
2825
import io.ktor.client.HttpClient
29-
import kotlinx.coroutines.CoroutineScope
3026
import kotlinx.coroutines.Deferred
31-
import kotlinx.coroutines.Dispatchers
3227
import kotlinx.coroutines.async
33-
import kotlinx.coroutines.awaitAll
34-
import kotlinx.coroutines.coroutineScope
35-
import kotlinx.coroutines.launch
3628
import kotlinx.coroutines.supervisorScope
3729

38-
class AppCoreManager : MultiDexApplication() , Application.ActivityLifecycleCallbacks , LifecycleObserver {
30+
class AppCoreManager : BaseCoreManager() {
3931

40-
private val dataStoreCoreManager : DataStoreCoreManager by lazy {
41-
DataStoreCoreManager(context = this)
42-
}
32+
private var currentActivity : Activity? = null
4333

44-
private val adsCoreManager : AdsCoreManager by lazy {
45-
AdsCoreManager(context = this)
46-
}
34+
companion object {
35+
@SuppressLint("StaticFieldLeak")
36+
lateinit var instance : AppCoreManager
37+
private set
4738

48-
private var currentActivity : Activity? = null
39+
lateinit var dataStore : DataStore
40+
private set
41+
42+
lateinit var database : AppDatabase
43+
private set
44+
45+
val adsCoreManager : AdsCoreManager by lazy {
46+
AdsCoreManager(context = instance)
47+
}
48+
49+
val ktorClient : HttpClient
50+
get() = BaseCoreManager.ktorClient
51+
52+
val isAppLoaded : Boolean
53+
get() = BaseCoreManager.isAppLoaded
54+
}
4955

5056
override fun onCreate() {
5157
super.onCreate()
5258
instance = this
53-
registerActivityLifecycleCallbacks(this)
5459

5560
val crashlyticsReporter = CrashlyticsErrorReporter()
5661
ErrorHandler.init(reporter = crashlyticsReporter)
5762

63+
registerActivityLifecycleCallbacks(this)
5864
ProcessLifecycleOwner.get().lifecycle.addObserver(observer = this)
59-
CoroutineScope(context = Dispatchers.IO).launch {
60-
initializeApp()
61-
}
6265
}
6366

64-
private suspend fun initializeApp() = supervisorScope {
65-
val ktor : Deferred<Unit> = async { initializeKtorClient() }
66-
val dataBase : Deferred<Unit> = async { initializeDatabase() }
67-
val dataStore : Deferred<Unit> = async { initializeDataStore() }
68-
69-
ktor.await()
70-
dataBase.await()
71-
dataStore.await()
72-
73-
adsCoreManager.initializeAds()
67+
override suspend fun onInitializeApp() = supervisorScope {
68+
val dataStoreInitialization : Deferred<Unit> = async { initializeDataStore() }
69+
val databaseInitialization : Deferred<Unit> = async { initializeDatabase() }
70+
val adsInitialization : Deferred<Unit> = async { initializeAds() }
7471

75-
initializeAds()
76-
finalizeInitialization()
72+
dataStoreInitialization.await()
73+
databaseInitialization.await()
74+
adsInitialization.await()
7775
}
7876

79-
private suspend fun initializeKtorClient() {
77+
private fun initializeDataStore() {
8078
runCatching {
81-
coroutineScope {
82-
val tasks : List<Deferred<Unit>> =
83-
listOf(element = async(context = Dispatchers.IO) {
84-
ktorClient = KtorClient().createClient()
85-
})
86-
tasks.awaitAll()
87-
}
79+
dataStore = DataStore.getInstance(context = this@AppCoreManager)
8880
}.onFailure {
8981
handleInitializationFailure(
90-
message = "Ktor client initialization failed" ,
91-
exception = it as Exception ,
92-
applicationContext = applicationContext
82+
message = "DataStore initialization failed" , exception = it as Exception , applicationContext = applicationContext
9383
)
9484
}
9585
}
9686

9787
private suspend fun initializeDatabase() {
9888
runCatching {
9989
database = Room.databaseBuilder(
100-
context = this@AppCoreManager,
101-
klass = AppDatabase::class.java,
102-
name = "Android Studio Tutorials"
103-
)
104-
.addMigrations(migrations = getMigrations())
105-
.fallbackToDestructiveMigration()
106-
.fallbackToDestructiveMigrationOnDowngrade()
107-
.build()
90+
context = this@AppCoreManager , klass = AppDatabase::class.java , name = "Android Studio Tutorials"
91+
).addMigrations(migrations = getMigrations()).fallbackToDestructiveMigration().fallbackToDestructiveMigrationOnDowngrade().build()
10892

10993
database.openHelper.writableDatabase
11094
}.onFailure {
11195
handleDatabaseError(exception = it as Exception)
11296
}
11397
}
11498

115-
private fun getMigrations() : Array<Migration> {
116-
return arrayOf(
117-
MIGRATION_1_2 ,
118-
MIGRATION_2_3 ,
119-
)
120-
}
121-
122-
private suspend fun initializeDataStore() {
123-
runCatching {
124-
dataStore = DataStore.getInstance(context = this@AppCoreManager)
125-
dataStoreCoreManager.initializeDataStore()
126-
}.onFailure {
127-
handleInitializationFailure(
128-
message = "DataStore initialization failed" ,
129-
exception = it as Exception ,
130-
applicationContext = applicationContext
131-
)
132-
}
133-
}
134-
135-
private fun initializeAds() {
136-
runCatching {
137-
adsCoreManager.initializeAds()
138-
}.onFailure {
139-
handleInitializationFailure(
140-
message = "Ads initialization failed" ,
141-
exception = it as Exception ,
142-
applicationContext = applicationContext
143-
)
144-
}
145-
}
146-
147-
private fun finalizeInitialization() {
148-
markAppAsLoaded()
149-
}
150-
151-
@OnLifecycleEvent(Lifecycle.Event.ON_START)
152-
fun onMoveToForeground() {
153-
currentActivity?.let { adsCoreManager.showAdIfAvailable(activity = it) }
154-
}
155-
15699
private suspend fun handleDatabaseError(exception : Exception) {
157100
if (exception is SQLiteException || (exception is IllegalStateException && exception.message?.contains(other = "Migration failed") == true)) {
158101
eraseDatabase()
@@ -173,44 +116,34 @@ class AppCoreManager : MultiDexApplication() , Application.ActivityLifecycleCall
173116
Log.e("AppCoreManager" , "Database error: ${exception.message}" , exception)
174117
}
175118

176-
private fun markAppAsLoaded() {
177-
isAppLoaded = true
119+
private fun initializeAds() {
120+
adsCoreManager.initializeAds(AdsConstants.APP_OPEN_UNIT_ID)
121+
}
122+
123+
private fun getMigrations() : Array<Migration> {
124+
return arrayOf(
125+
MIGRATION_1_2 , MIGRATION_2_3
126+
)
178127
}
179128

180129
fun isAppLoaded() : Boolean {
181130
return isAppLoaded
182131
}
183132

133+
@OnLifecycleEvent(Lifecycle.Event.ON_START)
134+
fun onMoveToForeground() {
135+
currentActivity?.let { adsCoreManager.showAdIfAvailable(it) }
136+
}
137+
184138
override fun onActivityCreated(activity : Activity , savedInstanceState : Bundle?) {}
185139

186140
override fun onActivityStarted(activity : Activity) {
187-
if (! adsCoreManager.isShowingAd) {
188-
currentActivity = activity
189-
}
141+
currentActivity = activity
190142
}
191143

192144
override fun onActivityResumed(activity : Activity) {}
193145
override fun onActivityPaused(activity : Activity) {}
194146
override fun onActivityStopped(activity : Activity) {}
195147
override fun onActivitySaveInstanceState(activity : Activity , outState : Bundle) {}
196148
override fun onActivityDestroyed(activity : Activity) {}
197-
198-
companion object {
199-
200-
lateinit var dataStore : DataStore
201-
private set
202-
203-
lateinit var database : AppDatabase
204-
private set
205-
206-
@SuppressLint("StaticFieldLeak")
207-
lateinit var instance : AppCoreManager
208-
private set
209-
210-
lateinit var ktorClient : HttpClient
211-
private set
212-
213-
var isAppLoaded : Boolean = false
214-
private set
215-
}
216149
}

0 commit comments

Comments
 (0)