Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8b1dc26
feat: Implement HomeScreen UI with mock data and strictly enforce no …
TheRealAshik May 15, 2026
b5d6400
Implement Repository and Pull Request screens
TheRealAshik May 15, 2026
f527295
feat: Implement Inbox and Explore screens UI
TheRealAshik May 15, 2026
2cfb519
feat: implement profile and repository list screens
TheRealAshik May 15, 2026
fe1a86e
Merge feat/inbox-explore-ui: resolve strings.xml conflict
TheRealAshik May 15, 2026
c13b26f
Merge feature/home-screen-ui: resolve strings.xml and MainScreen.kt c…
TheRealAshik May 15, 2026
9eeb2c4
Merge feature/implement-profile-and-repository-lists: resolve conflicts
TheRealAshik May 15, 2026
da59733
ci: add workflow_dispatch and develop branch trigger
TheRealAshik May 15, 2026
5b4ce11
fix: resolve Dimens JVM signature clash by unifying to PascalCase con…
TheRealAshik May 15, 2026
8efcb48
feat: Implement settings, notification options, code options, and acc…
TheRealAshik May 15, 2026
182444e
Merge feat/settings-screens: add settings strings
TheRealAshik May 15, 2026
1d31540
fix: replace hardcoded black with M3 light/dark color schemes
TheRealAshik May 15, 2026
12a1e4c
docs: update AGENTS.md with light/dark theme and Dimens rules
TheRealAshik May 15, 2026
6543b08
chore: remove parse_and_replace.py
TheRealAshik May 15, 2026
bd87889
Add Jetpack Navigation, PAT auth, and data layer
TheRealAshik May 15, 2026
f76ef65
feat: replace mock data with real GitHub API in Home and Profile screens
TheRealAshik May 15, 2026
f27dacf
feat: replace mock data with real GitHub API in RepositoryList screen
TheRealAshik May 15, 2026
2c4ffb9
fix: add missing retry string resource
TheRealAshik May 15, 2026
32c5e29
fix: replace hardcoded strings with stringResource
TheRealAshik May 15, 2026
16f44da
fix: add INTERNET permission and wire profile tab navigation
TheRealAshik May 15, 2026
cd4c525
Fix top app bar spacing and wire profile navigation
TheRealAshik May 15, 2026
2aa9e7b
Fix broken IconButton syntax in HomeScreen
TheRealAshik May 15, 2026
bc65a54
Update ProfileScreen to properly use ProfileUiState and display Proje…
TheRealAshik May 15, 2026
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
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ on:
push:
branches:
- master
- develop
pull_request:
workflow_dispatch:

jobs:
android:
Expand Down
13 changes: 12 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ composeApp/src/
### UI Design
- Follow **Material 3 Expressive** design guidelines — use expressive color roles, dynamic shapes, motion, and typography tokens from the M3 spec.
- Use `MaterialTheme` tokens (`colorScheme`, `typography`, `shapes`) exclusively; never hardcode colors or dimensions.
- Theme must support **both light and dark** modes using `lightColorScheme()` and `darkColorScheme()`. Switch automatically with `isSystemInDarkTheme()`. Never force a single theme or override colors with hardcoded values (e.g. `Color.Black`).
- Optimize layouts for all target platforms:
- **Mobile (Android/iOS):** single-column, touch-friendly tap targets (≥48dp), bottom navigation.
- **Desktop (JVM):** wider layouts with side navigation or rail, keyboard/mouse interactions, resizable windows.
Expand All @@ -59,9 +60,19 @@ composeApp/src/
- Never use Android or iOS APIs directly in `commonMain`. Use `expect/actual`.
- `androidMain` and `iosMain` contain only thin platform bridges.

## No Hardcoding Policy

Strict rules apply to all UI implementations. **NO EXCEPTIONS**:
- All user-visible strings → `strings.xml` + `stringResource()`
- All colors → `MaterialTheme.colorScheme.*` only
- All dimensions/spacing → `Dimens` object constants (PascalCase) or `MaterialTheme` tokens; never inline magic numbers
- All typography → `MaterialTheme.typography.*` only
- All shapes → `MaterialTheme.shapes.*` only
- Follow M3 Expressive: use expressive color roles, shape morphing, and motion tokens where applicable

## What Agents Should NOT Do

- Do not modify `local.properties`.
- Do not push directly to `main` — open a PR.
- Do not push directly to `main` or `develop` — open a PR targeting `develop`.
- Do not add new Gradle modules without discussion.
- Do not introduce new networking libraries; use the existing HTTP client.
14 changes: 14 additions & 0 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ plugins {
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
alias(libs.plugins.composeHotReload)
alias(libs.plugins.kotlinSerialization)
}

kotlin {
Expand Down Expand Up @@ -52,6 +53,12 @@ kotlin {
implementation(libs.compose.uiToolingPreview)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
implementation(libs.navigation.compose)
implementation(libs.kotlinx.serialization.json)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.auth)
}
}
val commonTest by getting {
Expand All @@ -63,6 +70,7 @@ kotlin {
dependencies {
implementation(libs.compose.uiToolingPreview)
implementation(libs.androidx.activity.compose)
implementation(libs.ktor.client.android)
}
}
val jvmMain by getting {
Expand All @@ -73,6 +81,9 @@ kotlin {
}
val webMain by creating {
dependsOn(commonMain)
dependencies {
implementation(libs.ktor.client.js)
}
}
val jsMain by getting {
dependsOn(webMain)
Expand All @@ -82,6 +93,9 @@ kotlin {
}
val iosMain by creating {
dependsOn(commonMain)
dependencies {
implementation(libs.ktor.client.darwin)
}
}
val iosArm64Main by getting {
dependsOn(iosMain)
Expand Down
2 changes: 2 additions & 0 deletions composeApp/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

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

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import dev.therealashik.github.data.initTokenStorage

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)

initTokenStorage(this)
setContent {
App()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.therealashik.github.data

import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences

private class AndroidTokenStorage(context: Context) : TokenStorage {
// TODO: Replace with EncryptedSharedPreferences for production
private val prefs: SharedPreferences =
context.getSharedPreferences("github_prefs", Context.MODE_PRIVATE)
Comment on lines +9 to +10
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Storing Personal Access Tokens (PAT) in plain text using SharedPreferences is insecure. As noted in the TODO, this should be replaced with EncryptedSharedPreferences from the Jetpack Security library to ensure sensitive credentials are encrypted at rest.


override fun saveToken(token: String) { prefs.edit().putString(KEY, token).apply() }
override fun getToken(): String? = prefs.getString(KEY, null)
override fun clearToken() { prefs.edit().remove(KEY).apply() }

companion object { private const val KEY = "pat_token" }
}

@SuppressLint("StaticFieldLeak")
private var appContext: Context? = null

fun initTokenStorage(context: Context) {
appContext = context.applicationContext
}

actual fun createTokenStorage(): TokenStorage =
AndroidTokenStorage(checkNotNull(appContext) { "Call initTokenStorage(context) in MainActivity.onCreate" })
Loading
Loading