-
Notifications
You must be signed in to change notification settings - Fork 7
QuickStart Apps - Android Tasks app #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d1932fb
ffe8022
af47e49
203f30f
628c57b
2339fd4
3f7a427
3c3a16e
24043b6
3affe44
fbbaaa3
9c02151
bba48a0
83055af
6cd234b
5cf3b75
4d15af3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,3 +28,5 @@ obj/ | |
| packages/ | ||
| target/ | ||
| xcuserdata | ||
| .env | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| *.iml | ||
| .gradle | ||
| /local.properties | ||
| /.idea/caches | ||
| /.idea/libraries | ||
| /.idea/modules.xml | ||
| /.idea/workspace.xml | ||
| /.idea/navEditor.xml | ||
| /.idea/assetWizardSettings.xml | ||
| .DS_Store | ||
| /build | ||
| /captures | ||
| .externalNativeBuild | ||
| .cxx | ||
| local.properties |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /build |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| import com.android.build.api.variant.BuildConfigField | ||
| import java.io.FileInputStream | ||
| import java.io.FileNotFoundException | ||
| import java.util.Properties | ||
|
|
||
| plugins { | ||
| alias(libs.plugins.android.application) | ||
| alias(libs.plugins.jetbrains.kotlin.android) | ||
| } | ||
|
|
||
| // Load properties from the .env file at the repository root | ||
| fun loadEnvProperties(): Properties { | ||
| val envFile = rootProject.file("../../.env") | ||
| val properties = Properties() | ||
| if (envFile.exists()) { | ||
| FileInputStream(envFile).use { properties.load(it) } | ||
| } else { | ||
| throw FileNotFoundException(".env file not found at: ${envFile.path}") | ||
| } | ||
| return properties | ||
| } | ||
|
|
||
| // Define BuildConfig.DITTO_APP_ID and BuildConfig.DITTO_PLAYGROUND_TOKEN | ||
| // based on values in the .env file | ||
| androidComponents { | ||
| onVariants { | ||
| val prop = loadEnvProperties() | ||
| it.buildConfigFields.put( | ||
| "DITTO_APP_ID", | ||
| BuildConfigField( | ||
| "String", | ||
| "\"${prop["DITTO_APP_ID"]}\"", | ||
| "Ditto application ID" | ||
| ) | ||
| ) | ||
| it.buildConfigFields.put( | ||
| "DITTO_PLAYGROUND_TOKEN", | ||
| BuildConfigField( | ||
| "String", | ||
| "\"${prop["DITTO_PLAYGROUND_TOKEN"]}\"", | ||
| "Ditto online playground authentication token" | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| android { | ||
| namespace = "live.ditto.quickstart.tasks" | ||
| compileSdk = 35 | ||
|
|
||
| defaultConfig { | ||
| applicationId = "live.ditto.quickstart.tasks" | ||
| minSdk = 23 | ||
| targetSdk = 35 | ||
| versionCode = 1 | ||
| versionName = "1.0" | ||
|
|
||
| testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||
| vectorDrawables { | ||
| useSupportLibrary = true | ||
| } | ||
| } | ||
|
|
||
| buildTypes { | ||
| release { | ||
| isMinifyEnabled = false | ||
| proguardFiles( | ||
| getDefaultProguardFile("proguard-android-optimize.txt"), | ||
| "proguard-rules.pro" | ||
| ) | ||
| } | ||
| } | ||
| compileOptions { | ||
| sourceCompatibility = JavaVersion.VERSION_1_8 | ||
| targetCompatibility = JavaVersion.VERSION_1_8 | ||
| } | ||
| kotlinOptions { | ||
| jvmTarget = "1.8" | ||
| } | ||
| buildFeatures { | ||
| buildConfig = true | ||
| compose = true | ||
| } | ||
| composeOptions { | ||
| kotlinCompilerExtensionVersion = "1.5.14" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not something that needs to be done in this PR, but since the kotlin compiler version will need to change with the kotlin dependencies, this would be a good value to extract into the version catalog. There are several examples in the Ditto Kotlin SDK of using the version catalog for arbitrary version numbers: https://github.com/getditto/ditto/blob/ba44fb0f182fe5274f976d0462ec7cfef421916f/android/ditto/build.gradle.kts#L32-L33
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll review that. I actually had a few problems with getting a compatible set of versions of the Kotlin compiler, gradle, Android |
||
| } | ||
| packaging { | ||
| resources { | ||
| excludes += "/META-INF/{AL2.0,LGPL2.1}" | ||
| } | ||
| } | ||
| } | ||
|
|
||
| dependencies { | ||
|
|
||
| implementation(libs.androidx.core.ktx) | ||
| implementation(libs.androidx.lifecycle.runtime.ktx) | ||
| implementation(libs.androidx.activity.compose) | ||
| implementation(platform(libs.androidx.compose.bom)) | ||
| implementation(libs.androidx.ui) | ||
| implementation(libs.androidx.ui.graphics) | ||
| implementation(libs.androidx.ui.tooling.preview) | ||
| implementation(libs.androidx.material3) | ||
| implementation(libs.androidx.navigation.compose) | ||
| implementation(libs.androidx.runtime.livedata) | ||
| implementation(libs.androidx.appcompat) | ||
| implementation(libs.androidx.datastore.preferences) | ||
|
|
||
| testImplementation(libs.junit) | ||
| androidTestImplementation(libs.androidx.junit) | ||
| androidTestImplementation(libs.androidx.espresso.core) | ||
| androidTestImplementation(platform(libs.androidx.compose.bom)) | ||
| androidTestImplementation(libs.androidx.ui.test.junit4) | ||
|
|
||
| debugImplementation(libs.androidx.ui.tooling) | ||
| debugImplementation(libs.androidx.ui.test.manifest) | ||
|
|
||
| // Ditto SDK | ||
| implementation("live.ditto:ditto:4.8.2") | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Add project specific ProGuard rules here. | ||
| # You can control the set of applied configuration files using the | ||
| # proguardFiles setting in build.gradle. | ||
| # | ||
| # For more details, see | ||
| # http://developer.android.com/guide/developing/tools/proguard.html | ||
|
|
||
| # If your project uses WebView with JS, uncomment the following | ||
| # and specify the fully qualified class name to the JavaScript interface | ||
| # class: | ||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
| # public *; | ||
| #} | ||
|
|
||
| # Uncomment this to preserve the line number information for | ||
| # debugging stack traces. | ||
| #-keepattributes SourceFile,LineNumberTable | ||
|
|
||
| # If you keep the line number information, uncomment this to | ||
| # hide the original source file name. | ||
| #-renamesourcefileattribute SourceFile |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package live.ditto.quickstart.tasks | ||
|
|
||
| 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("live.ditto.quickstart.tasks", appContext.packageName) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| xmlns:tools="http://schemas.android.com/tools"> | ||
|
|
||
| <!-- Required for Bluetooth --> | ||
| <uses-permission | ||
| android:name="android.permission.BLUETOOTH" | ||
| android:maxSdkVersion="30" /> | ||
| <uses-permission | ||
| android:name="android.permission.BLUETOOTH_ADMIN" | ||
| android:maxSdkVersion="30" /> | ||
| <uses-permission | ||
| android:name="android.permission.BLUETOOTH_ADVERTISE" | ||
| tools:targetApi="31" /> | ||
| <uses-permission | ||
| android:name="android.permission.BLUETOOTH_CONNECT" | ||
| tools:targetApi="31" /> | ||
| <uses-permission | ||
| android:name="android.permission.BLUETOOTH_SCAN" | ||
| android:usesPermissionFlags="neverForLocation" | ||
| tools:targetApi="31" /> | ||
| <uses-permission | ||
| android:name="android.permission.ACCESS_COARSE_LOCATION" | ||
| android:maxSdkVersion="30" /> | ||
|
|
||
| <!-- Required for WiFi Aware --> | ||
| <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> | ||
| <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> | ||
| <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||
| <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> | ||
| <uses-permission | ||
| android:name="android.permission.NEARBY_WIFI_DEVICES" | ||
| android:usesPermissionFlags="neverForLocation" | ||
| tools:targetApi="33" /> | ||
| <uses-permission | ||
| android:name="android.permission.ACCESS_FINE_LOCATION" | ||
| android:maxSdkVersion="32" /> | ||
|
|
||
| <!-- Required for WiFi Aware, TCP, UDP, and WebSockets --> | ||
| <uses-permission android:name="android.permission.INTERNET" /> | ||
|
|
||
| <!-- Required for mDNS discovery --> | ||
| <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> | ||
|
|
||
| <application | ||
| android:name=".TasksApplication" | ||
| android:allowBackup="true" | ||
| android:dataExtractionRules="@xml/data_extraction_rules" | ||
| android:fullBackupContent="@xml/backup_rules" | ||
| android:icon="@mipmap/ic_launcher" | ||
| android:label="@string/app_name" | ||
| android:roundIcon="@mipmap/ic_launcher_round" | ||
| android:supportsRtl="true" | ||
| android:theme="@style/Theme.QuickStartTasks" | ||
| tools:targetApi="31"> | ||
| <activity | ||
| android:name=".MainActivity" | ||
| android:exported="true" | ||
| android:label="@string/app_name" | ||
| android:theme="@style/Theme.QuickStartTasks"> | ||
| <intent-filter> | ||
| <action android:name="android.intent.action.MAIN" /> | ||
|
|
||
| <category android:name="android.intent.category.LAUNCHER" /> | ||
| </intent-filter> | ||
| </activity> | ||
| </application> | ||
|
|
||
| </manifest> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package live.ditto.quickstart.tasks | ||
|
|
||
| import live.ditto.* | ||
|
|
||
| class DittoHandler { | ||
| companion object { | ||
| lateinit var ditto: Ditto | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package live.ditto.quickstart.tasks | ||
|
|
||
| import android.os.Bundle | ||
| import androidx.activity.ComponentActivity | ||
| import androidx.activity.compose.setContent | ||
| import live.ditto.transports.DittoSyncPermissions | ||
|
|
||
| class MainActivity : ComponentActivity() { | ||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
|
|
||
| setContent { | ||
| Root() | ||
| } | ||
|
|
||
| requestMissingPermissions() | ||
| } | ||
|
|
||
| private fun requestMissingPermissions() { | ||
| val missingPermissions = DittoSyncPermissions(this).missingPermissions() | ||
| if (missingPermissions.isNotEmpty()) { | ||
| this.requestPermissions(missingPermissions, 0) | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package live.ditto.quickstart.tasks | ||
|
|
||
| import androidx.compose.material3.MaterialTheme | ||
| import androidx.compose.material3.Surface | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.navigation.compose.NavHost | ||
| import androidx.navigation.compose.composable | ||
| import androidx.navigation.compose.rememberNavController | ||
| import live.ditto.quickstart.tasks.edit.EditScreen | ||
| import live.ditto.quickstart.tasks.list.TasksListScreen | ||
| import live.ditto.quickstart.tasks.ui.theme.QuickStartTasksTheme | ||
|
|
||
| @Composable | ||
| fun Root() { | ||
| val navController = rememberNavController() | ||
|
|
||
| QuickStartTasksTheme { | ||
| // A surface container using the 'background' color from the theme | ||
| Surface(color = MaterialTheme.colorScheme.background) { | ||
| NavHost(navController = navController, startDestination = "tasks") { | ||
| composable("tasks") { TasksListScreen(navController = navController) } | ||
| composable("tasks/edit") { | ||
| EditScreen(navController = navController, taskId = null) | ||
| } | ||
| composable("tasks/edit/{taskId}") { backStackEntry -> | ||
| val taskId: String? = backStackEntry.arguments?.getString("taskId") | ||
| EditScreen(navController = navController, taskId = taskId) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| package live.ditto.quickstart.tasks | ||
|
|
||
| import android.app.Application | ||
| import android.content.Context | ||
| import live.ditto.Ditto | ||
| import live.ditto.DittoIdentity | ||
| import live.ditto.DittoLogLevel | ||
| import live.ditto.DittoLogger | ||
| import live.ditto.android.DefaultAndroidDittoDependencies | ||
| import live.ditto.quickstart.tasks.DittoHandler.Companion.ditto | ||
|
|
||
| class TasksApplication : Application() { | ||
|
|
||
| companion object { | ||
| private var instance: TasksApplication? = null | ||
|
|
||
| fun applicationContext(): Context { | ||
| return instance!!.applicationContext | ||
| } | ||
| } | ||
|
|
||
| init { | ||
| instance = this | ||
| } | ||
|
|
||
| override fun onCreate() { | ||
| super.onCreate() | ||
| setupDitto() | ||
| } | ||
|
|
||
| private fun setupDitto() { | ||
| val androidDependencies = DefaultAndroidDittoDependencies(applicationContext) | ||
| val appId = BuildConfig.DITTO_APP_ID | ||
| val token = BuildConfig.DITTO_PLAYGROUND_TOKEN | ||
| val enableDittoCloudSync = true | ||
|
|
||
| val identity = DittoIdentity.OnlinePlayground( | ||
| androidDependencies, | ||
| appId, | ||
| token, | ||
| enableDittoCloudSync | ||
| ) | ||
|
|
||
| ditto = Ditto(androidDependencies, identity) | ||
|
|
||
| DittoLogger.minimumLogLevel = DittoLogLevel.DEBUG | ||
|
|
||
| ditto.disableSyncWithV3() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't used this type of config before but it looks like a good way to reduce duplication when you're using the same properties in every build variant.