Skip to content

Commit c0e7d67

Browse files
committed
Implement JetPack Compose
This commit reimplements the UI with JetPack Compose.
1 parent 442f44f commit c0e7d67

File tree

93 files changed

+3719
-1251
lines changed

Some content is hidden

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

93 files changed

+3719
-1251
lines changed

.travis.yml

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
language: android
2+
jdk:
3+
- openjdk11
24
android:
35
components:
46
- tools

app/build.gradle

+39-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
apply plugin: 'com.android.application'
22
apply plugin: 'kotlin-android'
33
apply plugin: 'kotlin-kapt'
4-
apply plugin: "androidx.navigation.safeargs.kotlin"
4+
apply plugin: "androidx.navigation.safeargs"
55
apply plugin: 'com.google.firebase.crashlytics'
66
apply plugin: 'com.google.gms.google-services'
77
apply plugin: 'dagger.hilt.android.plugin'
8-
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
98
apply plugin: 'com.google.firebase.firebase-perf'
109
apply plugin: 'com.github.triplet.play'
10+
apply plugin: 'com.dicedmelon.gradle.jacoco-android'
1111

1212
android {
1313
compileSdkVersion Config.compile_sdk
@@ -28,10 +28,15 @@ android {
2828
// Version info
2929
buildConfigField 'String', 'GIT_SHA', "\"${project.ext.gitHash}\""
3030

31+
vectorDrawables {
32+
useSupportLibrary true
33+
}
34+
3135
javaCompileOptions.annotationProcessorOptions.arguments['room.schemaLocation'] = rootProject.file('schemas').toString()
3236
}
3337
buildFeatures {
3438
viewBinding true
39+
compose true
3540
}
3641
compileOptions {
3742
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -45,8 +50,12 @@ android {
4550
"-Xopt-in=kotlin.ExperimentalStdlibApi",
4651
"-Xopt-in=kotlin.time.ExperimentalTime",
4752
"-Xopt-in=kotlinx.coroutines.FlowPreview",
48-
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi"
53+
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
54+
"-Xopt-in=androidx.compose.foundation.ExperimentalFoundationApi",
55+
"-Xopt-in=androidx.compose.animation.ExperimentalAnimationApi",
56+
"-Xopt-in=androidx.compose.material.ExperimentalMaterialApi"
4957
]
58+
useIR = true
5059
}
5160
testOptions {
5261
unitTests {
@@ -105,6 +114,9 @@ android {
105114
exclude '**/NOTICE.txt'
106115
exclude '**/*.gwt.xml'
107116
}
117+
composeOptions {
118+
kotlinCompilerExtensionVersion Versions.androidXCompose
119+
}
108120
}
109121

110122
dependencies {
@@ -133,20 +145,38 @@ dependencies {
133145
implementation Libs.androidx_browser
134146
implementation Libs.androidx_constraint_layout
135147
implementation Libs.androidx_core
148+
implementation "androidx.core:core-splashscreen:1.0.0-alpha01"
136149
implementation Libs.androidx_fragment
137150
implementation Libs.androidx_hilt_work
138151
implementation Libs.androidx_lifecycle_viewmodel
152+
implementation Libs.androidx_lifecycle_livedata
139153
implementation Libs.androidx_lifecycle_java8
154+
implementation Libs.androidx_lifecycle_runtime
140155
implementation Libs.androidx_lifecycle_process
141156
implementation Libs.androidx_navigation_fragment
142157
implementation Libs.androidx_navigation_ui
158+
implementation "androidx.navigation:navigation-compose:$Versions.androidXNavigation"
143159
implementation Libs.androidx_preference
144160
implementation Libs.androidx_recyclerview
145161
implementation Libs.androidx_recyclerview_selection
146162
implementation Libs.androidx_room_runtime
147163
implementation Libs.androidx_room_ktx
148164
implementation Libs.androidx_work_runtime
149165
implementation Libs.androidx_work_gcm
166+
implementation 'com.google.android.material:material:1.4.0'
167+
implementation 'androidx.activity:activity-compose:1.3.0-rc02'
168+
implementation "androidx.compose.ui:ui:$Versions.androidXCompose"
169+
implementation "androidx.compose.foundation:foundation:$Versions.androidXCompose"
170+
implementation "androidx.compose.material:material:$Versions.androidXCompose"
171+
implementation "androidx.compose.material:material-icons-core:$Versions.androidXCompose"
172+
implementation "androidx.compose.material:material-icons-extended:$Versions.androidXCompose"
173+
// implementation "androidx.compose.ui:ui-tooling:$Versions.androidXCompose"
174+
implementation "androidx.compose.ui:ui-tooling:1.0.0-beta09"
175+
implementation "com.google.accompanist:accompanist-insets:0.14.0"
176+
177+
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
178+
implementation 'androidx.hilt:hilt-navigation-compose:1.0.0-alpha03'
179+
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$Versions.androidXCompose"
150180
kapt Libs.androidx_room_compiler
151181
kapt Libs.androidx_hilt_compiler
152182

@@ -182,8 +212,8 @@ dependencies {
182212
implementation Libs.kotlinCoroutinesAndroid
183213

184214
// LeakCanary
185-
debugImplementation Libs.leakCanary
186-
implementation Libs.leakCanaryPlumberAndroid
215+
// debugImplementation Libs.leakCanary
216+
// implementation Libs.leakCanaryPlumberAndroid
187217

188218
// Logging
189219
implementation Libs.slf4jAndroidLogger
@@ -200,6 +230,10 @@ kapt {
200230
correctErrorTypes true
201231
}
202232

233+
jacoco {
234+
toolVersion = "0.8.7"
235+
}
236+
203237
play {
204238
def serviceAccountFileName = "google-play-api.json"
205239
if (rootProject.file(serviceAccountFileName).exists()) {

app/src/main/AndroidManifest.xml

+18-12
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
android:roundIcon="@mipmap/ic_launcher_round"
2020
android:supportsRtl="true"
2121
android:theme="@style/AppTheme.NoActionBar">
22-
<activity android:name=".MainActivity">
22+
<activity
23+
android:name=".MainActivity"
24+
android:exported="true"
25+
android:windowSoftInputMode="adjustResize">
2326
<intent-filter>
2427
<action android:name="android.intent.action.MAIN" />
2528
<category android:name="android.intent.category.LAUNCHER" />
@@ -30,6 +33,7 @@
3033
android:name=".appwidget.ClickHandlingActivity"
3134
android:allowTaskReparenting="false"
3235
android:excludeFromRecents="true"
36+
android:exported="true"
3337
android:noHistory="true"
3438
android:taskAffinity=""
3539
android:theme="@android:style/Theme.NoDisplay">
@@ -46,13 +50,17 @@
4650
android:taskAffinity=""
4751
android:theme="@style/AppTheme.Dialog.NoActionBar" />
4852

49-
<activity android:name=".widgets.WidgetConfigActivity">
53+
<activity
54+
android:name=".widgets.ui.WidgetConfigActivity"
55+
android:exported="true">
5056
<intent-filter>
5157
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
5258
</intent-filter>
5359
</activity>
5460

55-
<receiver android:name=".appwidget.DDWidgetProvider">
61+
<receiver
62+
android:name=".appwidget.DDWidgetProvider"
63+
android:exported="true">
5664
<intent-filter>
5765
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
5866
</intent-filter>
@@ -65,21 +73,19 @@
6573
android:name=".receivers.UpdateReceiver"
6674
android:exported="false" />
6775

76+
<receiver
77+
android:name=".receivers.PinWidgetSuccessReceiver"
78+
android:exported="false" />
79+
6880
<service
6981
android:name=".appwidget.WidgetService"
7082
android:permission="android.permission.BIND_REMOTEVIEWS" />
7183

7284
<!-- Disable auto-init of WorkManager -->
7385
<provider
74-
android:name="androidx.startup.InitializationProvider"
75-
android:authorities="${applicationId}.androidx-startup"
76-
android:exported="false"
77-
tools:node="merge">
78-
<meta-data
79-
android:name="androidx.work.impl.WorkManagerInitializer"
80-
android:value="androidx.startup"
81-
tools:node="remove" />
82-
</provider>
86+
android:name="androidx.work.impl.WorkManagerInitializer"
87+
android:authorities="${applicationId}.workmanager-init"
88+
tools:node="remove" />
8389

8490
<!-- Configure Firebase Analytics -->
8591
<meta-data
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,26 @@
11
package de.psdev.devdrawer
22

3-
import android.os.Bundle
4-
import android.view.LayoutInflater
5-
import android.view.View
6-
import android.view.ViewGroup
7-
import androidx.annotation.CallSuper
83
import androidx.annotation.StringRes
94
import androidx.fragment.app.Fragment
105
import androidx.lifecycle.LifecycleCoroutineScope
116
import androidx.lifecycle.lifecycleScope
12-
import androidx.viewbinding.ViewBinding
137
import de.psdev.devdrawer.analytics.TrackingService
148
import javax.inject.Inject
159

16-
abstract class BaseFragment<T : ViewBinding> : Fragment() {
10+
open class BaseFragment : Fragment() {
1711

1812
@Inject
1913
lateinit var trackingService: TrackingService
20-
21-
private var _binding: T? = null
22-
// This property is only valid between onCreateView and onDestroyView.
23-
protected val binding get() = _binding!!
24-
2514
protected var toolbarTitle: CharSequence
2615
get() = requireActivity().title
2716
set(value) {
2817
requireActivity().title = value
2918
}
30-
31-
final override fun onCreateView(
32-
inflater: LayoutInflater,
33-
container: ViewGroup?,
34-
savedInstanceState: Bundle?
35-
): View = createViewBinding(inflater, container, savedInstanceState).also { viewBinding ->
36-
_binding = viewBinding
37-
}.root
38-
39-
protected abstract fun createViewBinding(
40-
inflater: LayoutInflater,
41-
container: ViewGroup?,
42-
savedInstanceState: Bundle?
43-
): T
44-
45-
@CallSuper
46-
override fun onDestroyView() {
47-
super.onDestroyView()
48-
_binding = null
49-
}
19+
val Fragment.viewLifecycleScope: LifecycleCoroutineScope
20+
get() = viewLifecycleOwner.lifecycleScope
5021

5122
protected fun updateToolbarTitle(@StringRes resId: Int) {
5223
requireActivity().setTitle(resId)
5324
trackingService.trackScreen(this::class.java, getString(resId))
5425
}
55-
56-
val Fragment.viewLifecycleScope: LifecycleCoroutineScope
57-
get() = viewLifecycleOwner.lifecycleScope
58-
59-
}
26+
}

app/src/main/java/de/psdev/devdrawer/DevDrawerApplication.kt

+10-7
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,23 @@ class DevDrawerApplication: Application(), Configuration.Provider {
2929
registerAppInstallationReceiver()
3030
setupWorkers()
3131
}.let {
32-
logger.warn("{} version {} ({}) took {}ms to init", this::class.java.simpleName, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, it)
32+
logger.warn(
33+
"{} version {} ({}) took {}ms to init",
34+
this::class.java.simpleName,
35+
BuildConfig.VERSION_NAME,
36+
BuildConfig.VERSION_CODE,
37+
it
38+
)
3339
}
3440
}
3541

3642
// ==========================================================================================================================
3743
// Configuration.Provider
3844
// ==========================================================================================================================
3945

40-
override fun getWorkManagerConfiguration(): Configuration {
41-
logger.warn { "getWorkManagerConfiguration" }
42-
return Configuration.Builder()
43-
.setWorkerFactory(workerFactory)
44-
.build()
45-
}
46+
override fun getWorkManagerConfiguration(): Configuration = Configuration.Builder()
47+
.setWorkerFactory(workerFactory)
48+
.build()
4649

4750
// ==========================================================================================================================
4851
// Private API
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package de.psdev.devdrawer
2+
3+
import androidx.annotation.StringRes
4+
import androidx.compose.material.icons.Icons
5+
import androidx.compose.material.icons.filled.Grid3x3
6+
import androidx.compose.material.icons.filled.Info
7+
import androidx.compose.material.icons.filled.Settings
8+
import androidx.compose.material.icons.filled.Widgets
9+
import androidx.compose.ui.graphics.vector.ImageVector
10+
import de.psdev.devdrawer.database.Widget
11+
import de.psdev.devdrawer.database.WidgetProfile
12+
13+
sealed class DevDrawerScreen(
14+
val route: String
15+
)
16+
17+
sealed class TopLevelScreen(route: String): DevDrawerScreen(route) {
18+
abstract val icon: ImageVector
19+
@get:StringRes abstract val label: Int
20+
}
21+
22+
object Widgets: TopLevelScreen(
23+
route = "widgets"
24+
) {
25+
override val icon: ImageVector = Icons.Filled.Widgets
26+
override val label: Int = R.string.widgets
27+
}
28+
29+
object Profiles: TopLevelScreen(
30+
route = "profiles"
31+
) {
32+
override val icon: ImageVector = Icons.Filled.Grid3x3
33+
override val label: Int = R.string.profiles
34+
}
35+
36+
object Settings: TopLevelScreen(
37+
route = "settings"
38+
) {
39+
override val icon: ImageVector = Icons.Filled.Settings
40+
override val label: Int = R.string.settings
41+
}
42+
43+
object AppInfo: TopLevelScreen(
44+
route = "info"
45+
) {
46+
override val icon: ImageVector = Icons.Filled.Info
47+
override val label: Int = R.string.app_info
48+
}
49+
50+
data class WidgetEditorDestination(
51+
val widget: Widget
52+
): DevDrawerScreen(route = "widgets/${widget.id}")
53+
54+
data class ProfileEditorDestination(
55+
val widgetProfile: WidgetProfile
56+
): DevDrawerScreen(route = "profiles/${widgetProfile.id}")

0 commit comments

Comments
 (0)