Skip to content

Commit 4cf3a84

Browse files
committed
HeliboardL fork with Gemini AI proofreading, toolbar improvements, and LeanBitLab branding
Features: - Gemini AI-powered proofreading and translation toolbar keys - Improved toolbar key backgrounds (squircle shape) - Incognito mode indicator on spacebar - LeanBitLab branding overlay on app icon - Gesture library downloader improvements
1 parent 90bc107 commit 4cf3a84

32 files changed

Lines changed: 3213 additions & 1069 deletions

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ app/.cxx
1212
app/.attach_*
1313
fastlane/Appfile
1414
tools/*.txt
15+
16+
# Keys & Secrets (per build-checklist.md)
17+
*.jks
18+
*.keystore
19+
keystore.properties
20+
signing.properties

app/build.gradle.kts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import com.android.build.api.variant.ApplicationVariant
2+
import java.util.Properties
23

34
plugins {
45
id("com.android.application")
@@ -7,11 +8,18 @@ plugins {
78
kotlin("plugin.compose") version "2.2.21"
89
}
910

11+
// Load keystore properties
12+
val keystorePropertiesFile = rootProject.file("keystore.properties")
13+
val keystoreProperties = Properties()
14+
if (keystorePropertiesFile.exists()) {
15+
keystoreProperties.load(keystorePropertiesFile.inputStream())
16+
}
17+
1018
android {
1119
compileSdk = 35
1220

1321
defaultConfig {
14-
applicationId = "helium314.keyboard"
22+
applicationId = "helium314.keyboardl"
1523
minSdk = 21
1624
targetSdk = 35
1725
versionCode = 3603
@@ -23,12 +31,26 @@ android {
2331
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
2432
}
2533

34+
signingConfigs {
35+
if (keystorePropertiesFile.exists()) {
36+
create("release") {
37+
keyAlias = keystoreProperties["keyAlias"] as String
38+
keyPassword = keystoreProperties["keyPassword"] as String
39+
storeFile = rootProject.file(keystoreProperties["storeFile"] as String)
40+
storePassword = keystoreProperties["storePassword"] as String
41+
}
42+
}
43+
}
44+
2645
buildTypes {
2746
release {
2847
isMinifyEnabled = true
2948
isShrinkResources = false
3049
isDebuggable = false
3150
isJniDebuggable = false
51+
if (keystorePropertiesFile.exists()) {
52+
signingConfig = signingConfigs.getByName("release")
53+
}
3254
}
3355
create("nouserlib") { // same as release, but does not allow the user to provide a library
3456
isMinifyEnabled = true
@@ -54,7 +76,7 @@ android {
5476
signingConfig = signingConfigs.getByName("debug")
5577
applicationIdSuffix = ".debug"
5678
}
57-
base.archivesBaseName = "HeliBoard_" + defaultConfig.versionName
79+
base.archivesBaseName = "HeliboardL_" + defaultConfig.versionName
5880
// got a little too big for GitHub after some dependency upgrades, so we remove the largest dictionary
5981
androidComponents.onVariants { variant: ApplicationVariant ->
6082
if (variant.buildType == "debug") {
@@ -136,6 +158,10 @@ dependencies {
136158
implementation("sh.calvin.reorderable:reorderable:2.4.3") // for easier re-ordering, todo: check 3.0.0
137159
implementation("com.github.skydoves:colorpicker-compose:1.1.3") // for user-defined colors
138160

161+
// gemini ai proofreading
162+
implementation("com.google.ai.client.generativeai:generativeai:0.9.0")
163+
implementation("androidx.security:security-crypto:1.1.0-alpha06") // for encrypted API key storage
164+
139165
// test
140166
testImplementation(kotlin("test"))
141167
testImplementation("junit:junit:4.13.2")

app/proguard-rules.pro

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,15 @@
1212
# after upgrading to gradle 8, stack traces contain "unknown source"
1313
-keepattributes SourceFile,LineNumberTable
1414
-dontobfuscate
15+
16+
# Gemini SDK dependencies
17+
-dontwarn com.google.errorprone.annotations.CanIgnoreReturnValue
18+
-dontwarn com.google.errorprone.annotations.CheckReturnValue
19+
-dontwarn com.google.errorprone.annotations.Immutable
20+
-dontwarn com.google.errorprone.annotations.RestrictedApi
21+
22+
# Keep Gemini API classes
23+
-keep class com.google.ai.client.generativeai.** { *; }
24+
-keep class helium314.keyboard.latin.utils.GeminiProofreadService { *; }
25+
-keep class helium314.keyboard.latin.utils.ProofreadHelper { *; }
26+
-keep class helium314.keyboard.latin.utils.ProofreadHelper$* { *; }

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
1313
<uses-permission android:name="android.permission.VIBRATE" />
1414
<uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
1515
<uses-permission android:name="android.permission.READ_CONTACTS" />
16+
<uses-permission android:name="android.permission.INTERNET" />
1617

1718
<application android:label="@string/english_ime_name"
1819
android:name="helium314.keyboard.latin.App"

app/src/main/java/helium314/keyboard/keyboard/KeyboardActionListenerImpl.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import kotlin.math.min
3131

3232
class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inputLogic: InputLogic) : KeyboardActionListener {
3333

34-
private val connection = inputLogic.mConnection
34+
private val connection = inputLogic.connection
3535
private val emojiAltPhysicalKeyDetector by lazy { EmojiAltPhysicalKeyDetector(latinIME.resources) }
3636

3737
// We expect to have only one decoder in almost all cases, hence the default capacity of 1.
@@ -68,8 +68,7 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
6868
if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED)
6969
return false
7070

71-
val keyIdentifier = keyEvent.deviceId.toLong() shl 32 + keyEvent.keyCode
72-
return inputLogic.mCurrentlyPressedHardwareKeys.remove(keyIdentifier)
71+
return false
7372
}
7473

7574
override fun onKeyDown(keyCode: Int, keyEvent: KeyEvent): Boolean {
@@ -102,7 +101,12 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
102101
override fun onCodeInput(primaryCode: Int, x: Int, y: Int, isKeyRepeat: Boolean) {
103102
when (primaryCode) {
104103
KeyCode.TOGGLE_AUTOCORRECT -> return settings.toggleAutoCorrect()
105-
KeyCode.TOGGLE_INCOGNITO_MODE -> return settings.toggleAlwaysIncognitoMode()
104+
KeyCode.TOGGLE_INCOGNITO_MODE -> {
105+
settings.toggleAlwaysIncognitoMode()
106+
// Invalidate keyboard to update spacebar incognito icon immediately
107+
keyboardSwitcher.mainKeyboardView?.invalidateAllKeys()
108+
return
109+
}
106110
}
107111
val mkv = keyboardSwitcher.mainKeyboardView
108112

0 commit comments

Comments
 (0)