Skip to content
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

Feat Starter Kit #1

Merged
merged 4 commits into from
Feb 8, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: android starter kit.
ItzNotABug committed Jan 16, 2025
commit 8ba18e15665f7a3941cee4eac865fa63456c556a
10 changes: 10 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
*.iml
.gradle
.idea
build
gradle
local.properties
.externalNativeBuild

/captures
.DS_Store
68 changes: 68 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}

android {
namespace = "io.appwrite.starterkit"
compileSdk = 35

defaultConfig {
minSdk = 21
targetSdk = 35
versionCode = 1
versionName = "1.0"
applicationId = "io.appwrite.starterkit"
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "11"
}

buildFeatures {
compose = true
}
}

dependencies {
// appwrite
implementation(libs.appwrite)

// splashscreen
implementation(libs.androidx.core.splashscreen)

// core, compose and runtime
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)

// ui, preview & material
implementation(libs.androidx.ui)
implementation(libs.androidx.material3)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)

// compose platform
implementation(platform(libs.androidx.compose.bom))

// debug libraries
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
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
24 changes: 24 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="AppwriteStarterKit"
android:supportsRtl="true"
android:theme="@style/Theme.AppwriteStarterKit.SplashTheme"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
138 changes: 138 additions & 0 deletions app/src/main/java/io/appwrite/starterkit/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package io.appwrite.starterkit

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.RestrictTo
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import androidx.lifecycle.viewmodel.compose.viewModel
import io.appwrite.starterkit.data.models.Status
import io.appwrite.starterkit.data.models.mockProjectInfo
import io.appwrite.starterkit.extensions.copy
import io.appwrite.starterkit.extensions.edgeToEdgeWithStyle
import io.appwrite.starterkit.ui.components.CollapsibleBottomSheet
import io.appwrite.starterkit.ui.components.ConnectionStatusView
import io.appwrite.starterkit.ui.components.GettingStartedCards
import io.appwrite.starterkit.ui.components.TopPlatformView
import io.appwrite.starterkit.ui.components.addCheckeredBackground
import io.appwrite.starterkit.ui.theme.AppwriteStarterKitTheme
import io.appwrite.starterkit.viewmodels.AppwriteViewModel
import kotlinx.coroutines.delay

/**
* MainActivity serves as the entry point for the application.
* It configures the system's edge-to-edge settings, splash screen, and initializes the composable layout.
*/
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)

edgeToEdgeWithStyle()
WindowCompat.setDecorFitsSystemWindows(window, false)

setContent { AppwriteStarter() }
}
}

/**
* AppwriteStarter is the root composable function that sets up the main UI layout.
* It manages the logs, status, and project information using the provided [AppwriteViewModel].
*/
@Composable
fun AppwriteStarter(
viewModel: AppwriteViewModel = viewModel(),
) {
val logs by viewModel.logs.collectAsState()
val status by viewModel.status.collectAsState()

// data doesn't change, so no `remember`.
val projectInfo = viewModel.getProjectInfo()

AppwriteStarterKitTheme {
Scaffold(bottomBar = {
CollapsibleBottomSheet(
logs = logs,
projectInfo = projectInfo
)
}) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.addCheckeredBackground()
.padding(innerPadding.copy(top = 16.dp, bottom = 0.dp))
.windowInsetsPadding(WindowInsets.systemBars)
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
TopPlatformView(
status = status
)

ConnectionStatusView(status) {
viewModel.ping()
}

GettingStartedCards()
}
}
}
}

@Preview
@Composable
@RestrictTo(RestrictTo.Scope.TESTS)
private fun AppwriteStarterPreview() {
val status = remember { mutableStateOf<Status>(Status.Idle) }

AppwriteStarterKitTheme {
Scaffold(bottomBar = {
CollapsibleBottomSheet(
logs = emptyList(),
projectInfo = mockProjectInfo
)
}) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.addCheckeredBackground()
.padding(innerPadding.copy(top = 16.dp, bottom = 0.dp))
.windowInsetsPadding(WindowInsets.systemBars)
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
TopPlatformView(
status = status.value
)

ConnectionStatusView(status.value) {
// simulate a success ping
status.value = Status.Loading
delay(1000)
status.value = Status.Success
}

GettingStartedCards()
}
}
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/io/appwrite/starterkit/data/models/Log.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.appwrite.starterkit.data.models

/**
* A data model for holding log entries.
*/
data class Log(
val date: String,
val status: String,
val method: String,
val path: String,
val response: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.appwrite.starterkit.data.models

import androidx.annotation.RestrictTo

/**
* A data model for holding appwrite project information.
*/
data class ProjectInfo(
val endpoint: String,
val projectId: String,
val projectName: String,
val version: String,
)

/**
* A mock `ProjectInfo` model, just for **previews**.
*/
@RestrictTo(RestrictTo.Scope.TESTS)
internal val mockProjectInfo = ProjectInfo(
endpoint = "https://mock.api/v1",
projectId = "sample-project-id",
projectName = "AppwriteStarter",
version = "1.6.0",
)
27 changes: 27 additions & 0 deletions app/src/main/java/io/appwrite/starterkit/data/models/Status.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.appwrite.starterkit.data.models

/**
* Represents the various states of a process or operation.
* This sealed class ensures that only predefined statuses are used.
*/
sealed class Status {
/**
* Represents the idle state.
*/
data object Idle : Status()

/**
* Represents a loading state.
*/
data object Loading : Status()

/**
* Represents a successful operation.
*/
data object Success : Status()

/**
* Represents an error state.
*/
data object Error : Status()
}
Loading