Skip to content

Commit 8b9bf69

Browse files
author
LeanBitLab
committed
feat: Release v1.3 - Font Selection & UI Refinements
- Added Font Style selector with 11 system fonts - Implemented Transparent Background with text outlines - Refined Settings UI (Compact Layout, Dropdown Menus) - Fixed calendar event font consistency
1 parent 4752fdb commit 8b9bf69

40 files changed

Lines changed: 3486 additions & 82 deletions

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ android {
1414
applicationId = "com.leanbitlab.lwidget"
1515
minSdk = 26
1616
targetSdk = 34
17-
versionCode = 3
18-
versionName = "1.2"
17+
versionCode = 4
18+
versionName = "1.3"
1919
}
2020

2121
signingConfigs {

app/src/main/java/com/leanbitlab/lwidget/AwidgetProvider.kt

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,14 @@ class AwidgetProvider : AppWidgetProvider() {
8787
const val ACTION_BATTERY_UPDATE = "com.leanbitlab.lwidget.ACTION_BATTERY_UPDATE"
8888

8989
fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
90-
val views = RemoteViews(context.packageName, R.layout.widget_layout)
9190
val prefs = context.getSharedPreferences("com.leanbitlab.lwidget.PREFS", Context.MODE_PRIVATE)
9291

9392
// --- Load Preferences ---
9493
val showTime = prefs.getBoolean("show_time", true)
9594
val sizeTime = prefs.getFloat("size_time", 48f)
9695

9796
val showDate = prefs.getBoolean("show_date", true)
98-
val sizeDate = prefs.getFloat("size_date", 14f) // Note: Default in XML was 18sp, user asked for smaller events, standardizing defaults? XML is 18sp. Setting default to 18f to match.
97+
val sizeDate = prefs.getFloat("size_date", 14f)
9998

10099
val showBattery = prefs.getBoolean("show_battery", true)
101100
val sizeBattery = prefs.getFloat("size_battery", 48f)
@@ -105,35 +104,119 @@ class AwidgetProvider : AppWidgetProvider() {
105104

106105
val showEvents = prefs.getBoolean("show_events", true)
107106
val sizeEvents = prefs.getFloat("size_events", 14f)
108-
107+
109108
val showOutline = prefs.getBoolean("show_outline", false)
110109
val useLightTheme = prefs.getBoolean("use_light_theme", false)
110+
val isTransparent = prefs.getBoolean("transparent_background", false)
111+
val fontStyle = prefs.getInt("font_style", 0)
112+
// 0=Def, 1=Serif, 2=Mono, 3=Cursive, 4=Cond, 5=CondLight, 6=Light, 7=Med, 8=Black, 9=Thin, 10=SmallCaps
113+
114+
// --- Theme & Font Setup ---
115+
// Helper to get layout ID
116+
fun getLayout(baseLayoutId: Int, fontIdx: Int): Int {
117+
// If base is widget_layout
118+
if (baseLayoutId == R.layout.widget_layout) {
119+
return when (fontIdx) {
120+
1 -> R.layout.widget_layout_serif
121+
2 -> R.layout.widget_layout_mono
122+
3 -> R.layout.widget_layout_cursive
123+
4 -> R.layout.widget_layout_condensed
124+
5 -> R.layout.widget_layout_condensed_light
125+
6 -> R.layout.widget_layout_light
126+
7 -> R.layout.widget_layout_medium
127+
8 -> R.layout.widget_layout_black
128+
9 -> R.layout.widget_layout_thin
129+
10 -> R.layout.widget_layout_smallcaps
130+
else -> R.layout.widget_layout
131+
}
132+
}
133+
// If base is transparent dark
134+
if (baseLayoutId == R.layout.widget_layout_transparent_dark) {
135+
return when (fontIdx) {
136+
1 -> R.layout.widget_layout_transparent_dark_serif
137+
2 -> R.layout.widget_layout_transparent_dark_mono
138+
3 -> R.layout.widget_layout_transparent_dark_cursive
139+
4 -> R.layout.widget_layout_transparent_dark_condensed
140+
5 -> R.layout.widget_layout_transparent_dark_condensed_light
141+
6 -> R.layout.widget_layout_transparent_dark_light
142+
7 -> R.layout.widget_layout_transparent_dark_medium
143+
8 -> R.layout.widget_layout_transparent_dark_black
144+
9 -> R.layout.widget_layout_transparent_dark_thin
145+
10 -> R.layout.widget_layout_transparent_dark_smallcaps
146+
else -> R.layout.widget_layout_transparent_dark
147+
}
148+
}
149+
// If base is transparent light
150+
if (baseLayoutId == R.layout.widget_layout_transparent_light) {
151+
return when (fontIdx) {
152+
1 -> R.layout.widget_layout_transparent_light_serif
153+
2 -> R.layout.widget_layout_transparent_light_mono
154+
3 -> R.layout.widget_layout_transparent_light_cursive
155+
4 -> R.layout.widget_layout_transparent_light_condensed
156+
5 -> R.layout.widget_layout_transparent_light_condensed_light
157+
6 -> R.layout.widget_layout_transparent_light_light
158+
7 -> R.layout.widget_layout_transparent_light_medium
159+
8 -> R.layout.widget_layout_transparent_light_black
160+
9 -> R.layout.widget_layout_transparent_light_thin
161+
10 -> R.layout.widget_layout_transparent_light_smallcaps
162+
else -> R.layout.widget_layout_transparent_light
163+
}
164+
}
165+
return baseLayoutId
166+
}
111167

112-
// --- Theme Setup ---
113-
val bgRes = if (useLightTheme) {
114-
if (showOutline) R.drawable.background_glow_light else R.drawable.background_light
168+
val baseLayoutId = if (isTransparent) {
169+
if (useLightTheme) R.layout.widget_layout_transparent_light else R.layout.widget_layout_transparent_dark
115170
} else {
116-
if (showOutline) R.drawable.background_glow else R.drawable.background_dark
171+
R.layout.widget_layout
117172
}
173+
174+
val layoutId = getLayout(baseLayoutId, fontStyle)
118175

119-
val primaryColor = if (useLightTheme) {
120-
context.getColor(R.color.widget_text_light)
121-
} else {
122-
android.graphics.Color.WHITE
176+
val views = RemoteViews(context.packageName, layoutId)
177+
178+
// Only set background if NOT transparent
179+
if (!isTransparent) {
180+
val bgRes = if (useLightTheme) {
181+
if (showOutline) R.drawable.background_glow_light else R.drawable.background_light
182+
} else {
183+
if (showOutline) R.drawable.background_glow else R.drawable.background_dark
184+
}
185+
views.setInt(R.id.widget_root, "setBackgroundResource", bgRes)
123186
}
124187

125-
val secondaryColor = if (useLightTheme) {
126-
context.getColor(R.color.widget_text_secondary_light)
188+
// Colors for manual text setting (though transparent layouts handle most via XML styles)
189+
// We still need these for dynamic updates if we were using same layout, but since we swap layouts,
190+
// the XML attributes in transparent layouts (shadows, colors) handle static text.
191+
// However, we still programmatically set colors for consistecy in shared logic (like battery/events).
192+
193+
// For Transparent:
194+
// Dark (White Text, Black Outline) -> Primary: White, Secondary: White
195+
// Light (Black Text, White Outline) -> Primary: Black, Secondary: Black
196+
197+
// For Standard (Non-Transparent):
198+
// Dark -> Primary: White, Secondary: Light Gray
199+
// Light -> Primary: Black, Secondary: Dark Gray
200+
201+
val primaryColor = if (isTransparent) {
202+
if (useLightTheme) android.graphics.Color.BLACK else android.graphics.Color.WHITE
127203
} else {
128-
android.graphics.Color.parseColor("#CCFFFFFF")
204+
if (useLightTheme) context.getColor(R.color.widget_text_light) else android.graphics.Color.WHITE
129205
}
130206

131-
// --- Apply Outline / Background ---
132-
views.setInt(R.id.widget_root, "setBackgroundResource", bgRes)
207+
val secondaryColor = if (isTransparent) {
208+
if (useLightTheme) android.graphics.Color.BLACK else android.graphics.Color.WHITE
209+
} else {
210+
if (useLightTheme) context.getColor(R.color.widget_text_secondary_light) else android.graphics.Color.parseColor("#CCFFFFFF")
211+
}
133212

134213
// --- Apply Time ---
135214
views.setViewVisibility(R.id.clock_time, if (showTime) android.view.View.VISIBLE else android.view.View.GONE)
136215
views.setTextViewTextSize(R.id.clock_time, android.util.TypedValue.COMPLEX_UNIT_SP, sizeTime)
216+
// In transparent mode, XML handles shadow/color better to ensure outline presence,
217+
// but setting textColor here might override XML if not careful.
218+
// RemoteViews.setTextColor REPLACES the color. It does NOT remove shadow.
219+
// So it is safe to set color here.
137220
views.setTextColor(R.id.clock_time, primaryColor)
138221

139222
// --- Apply Date ---
@@ -145,7 +228,7 @@ class AwidgetProvider : AppWidgetProvider() {
145228
views.setViewVisibility(R.id.text_battery, if (showBattery) android.view.View.VISIBLE else android.view.View.GONE)
146229
views.setTextViewTextSize(R.id.text_battery, android.util.TypedValue.COMPLEX_UNIT_SP, sizeBattery)
147230
views.setTextColor(R.id.text_battery, primaryColor)
148-
231+
149232
views.setViewVisibility(R.id.text_temp, if (showTemp) android.view.View.VISIBLE else android.view.View.GONE)
150233
views.setTextViewTextSize(R.id.text_temp, android.util.TypedValue.COMPLEX_UNIT_SP, sizeTemp)
151234
views.setTextColor(R.id.text_temp, secondaryColor)

app/src/main/java/com/leanbitlab/lwidget/MainActivity.kt

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ class MainActivity : AppCompatActivity() {
102102

103103
// Light Theme: Def False
104104
bindToggle(R.id.section_theme, "Light Theme", "use_light_theme", false)
105+
106+
// Transparent Background: Def False
107+
bindToggle(R.id.section_transparent, "Transparent Background", "transparent_background", false)
108+
109+
// Font Style: Def "Default"
110+
bindFontSelector()
105111
}
106112

107113
private fun bindSection(
@@ -117,9 +123,10 @@ class MainActivity : AppCompatActivity() {
117123
val section = findViewById<View>(sectionId)
118124
val tvTitle = section.findViewById<TextView>(R.id.item_title)
119125
val switch = section.findViewById<SwitchMaterial>(R.id.item_switch)
126+
// size_container is now inside the same layout
127+
val sizeContainer = section.findViewById<View>(R.id.size_container)
120128
val slider = section.findViewById<Slider>(R.id.item_slider)
121129
val tvSize = section.findViewById<TextView>(R.id.size_label)
122-
val sizeContainer = section.findViewById<View>(R.id.size_container)
123130

124131
tvTitle.text = title
125132

@@ -139,13 +146,14 @@ class MainActivity : AppCompatActivity() {
139146
slider.valueFrom = minSize
140147
slider.valueTo = maxSize
141148
slider.value = currentSize.coerceIn(minSize, maxSize)
142-
tvSize.text = "Size: ${currentSize.toInt()}sp"
149+
tvSize.text = "${currentSize.toInt()}"
143150

144151
slider.addOnChangeListener { _, value, fromUser ->
145152
if (fromUser) {
146-
tvSize.text = "Size: ${value.toInt()}sp"
153+
tvSize.text = "${value.toInt()}"
147154
prefs.edit().putFloat(prefSizeKey, value).apply()
148-
updateWidget() // Live update
155+
// Debounce update? For now live is fine
156+
updateWidget()
149157
}
150158
}
151159
}
@@ -174,6 +182,35 @@ class MainActivity : AppCompatActivity() {
174182
}
175183
}
176184

185+
private fun bindFontSelector() {
186+
val section = findViewById<View>(R.id.section_font)
187+
// Note: setting_selector_item.xml structure changed
188+
// Root is LinearLayout, contains TextInputLayout -> AutoCompleteTextView
189+
val tvTitle = section.findViewById<TextView>(R.id.item_title)
190+
val autoCompleteTextView = section.findViewById<android.widget.AutoCompleteTextView>(R.id.item_value)
191+
192+
tvTitle.text = "Font Style"
193+
194+
val fonts = listOf(
195+
"Default", "Serif", "Monospace", "Cursive",
196+
"Condensed", "Condensed Light", "Light", "Medium",
197+
"Black", "Thin", "Small Caps"
198+
)
199+
200+
val adapter = android.widget.ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, fonts)
201+
autoCompleteTextView.setAdapter(adapter)
202+
203+
// Set current value
204+
val currentFontIdx = prefs.getInt("font_style", 0)
205+
autoCompleteTextView.setText(fonts.getOrElse(currentFontIdx) { "Default" }, false)
206+
207+
autoCompleteTextView.setOnItemClickListener { _, _, position, _ ->
208+
// position in the adapter corresponds to our index if list is same
209+
prefs.edit().putInt("font_style", position).apply()
210+
updateWidget()
211+
}
212+
}
213+
177214
private fun updateWidget() {
178215
// Animation: Subtle Outline Shine
179216
val fab = findViewById<ExtendedFloatingActionButton>(R.id.fab_update)

app/src/main/res/layout/activity_main.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@
9292
<!-- Light Theme Settings -->
9393
<include layout="@layout/settings_card_item" android:id="@+id/section_theme"/>
9494

95+
<!-- Transparent Settings -->
96+
<include layout="@layout/settings_card_item" android:id="@+id/section_transparent"/>
97+
98+
<!-- Font Settings -->
99+
<include layout="@layout/settings_selector_item" android:id="@+id/section_font"/>
100+
95101
<!-- Outline Glow Settings -->
96102
<include layout="@layout/settings_card_item" android:id="@+id/section_outline"/>
97103

Lines changed: 51 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,64 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
44
android:layout_width="match_parent"
55
android:layout_height="wrap_content"
6-
android:layout_marginBottom="12dp"
7-
app:cardBackgroundColor="?attr/colorSurfaceContainer"
8-
app:strokeColor="?attr/colorOutline"
9-
app:strokeWidth="1dp"
10-
app:cardCornerRadius="16dp"
11-
app:cardElevation="2dp">
6+
android:orientation="horizontal"
7+
android:gravity="center_vertical"
8+
android:paddingStart="16dp"
9+
android:paddingEnd="16dp"
10+
android:paddingTop="12dp"
11+
android:paddingBottom="12dp"
12+
android:background="?attr/selectableItemBackground">
1213

14+
<TextView
15+
android:id="@+id/item_title"
16+
android:layout_width="0dp"
17+
android:layout_height="wrap_content"
18+
android:layout_weight="1"
19+
android:text="Title"
20+
android:textColor="?attr/colorOnSurface"
21+
android:textSize="16sp"
22+
android:textStyle="bold" />
23+
24+
<!-- Container for Size Controls (Slider + Value) -->
1325
<LinearLayout
14-
android:layout_width="match_parent"
26+
android:id="@+id/size_container"
27+
android:layout_width="wrap_content"
1528
android:layout_height="wrap_content"
16-
android:orientation="vertical"
17-
android:padding="16dp">
29+
android:orientation="horizontal"
30+
android:gravity="center_vertical"
31+
android:visibility="gone">
1832

19-
<LinearLayout
20-
android:layout_width="match_parent"
33+
<TextView
34+
android:id="@+id/size_label"
35+
android:layout_width="wrap_content"
2136
android:layout_height="wrap_content"
22-
android:orientation="horizontal"
23-
android:gravity="center_vertical">
24-
25-
<TextView
26-
android:id="@+id/item_title"
27-
android:layout_width="0dp"
28-
android:layout_height="wrap_content"
29-
android:layout_weight="1"
30-
android:text="Component Name"
31-
android:textColor="?attr/colorOnSurface"
32-
android:textSize="18sp"
33-
android:textStyle="bold"/>
34-
35-
<com.google.android.material.switchmaterial.SwitchMaterial
36-
android:id="@+id/item_switch"
37-
android:layout_width="wrap_content"
38-
android:layout_height="wrap_content"
39-
android:saveEnabled="false"
40-
app:thumbTint="?attr/colorOnPrimaryContainer"
41-
app:trackTint="?attr/colorPrimaryContainer"/>
42-
</LinearLayout>
37+
android:text="14"
38+
android:textColor="?attr/colorOnSurfaceVariant"
39+
android:textSize="14sp"
40+
android:layout_marginEnd="4dp" />
4341

44-
<LinearLayout
45-
android:id="@+id/size_container"
46-
android:layout_width="match_parent"
42+
<com.google.android.material.slider.Slider
43+
android:id="@+id/item_slider"
44+
android:layout_width="120dp"
4745
android:layout_height="wrap_content"
48-
android:orientation="vertical"
49-
android:layout_marginTop="12dp">
50-
51-
<TextView
52-
android:id="@+id/size_label"
53-
android:layout_width="wrap_content"
54-
android:layout_height="wrap_content"
55-
android:text="Size: 14sp"
56-
android:textColor="?attr/colorOnSurfaceVariant"
57-
android:textSize="12sp"/>
58-
59-
<com.google.android.material.slider.Slider
60-
android:id="@+id/item_slider"
61-
android:layout_width="match_parent"
62-
android:layout_height="wrap_content"
63-
android:saveEnabled="false"
64-
android:valueFrom="8.0"
65-
android:valueTo="72.0"
66-
android:stepSize="1.0"
67-
app:thumbColor="?attr/colorPrimary"
68-
app:trackColorActive="?attr/colorPrimary"/>
69-
</LinearLayout>
46+
android:saveEnabled="false"
47+
android:valueFrom="8.0"
48+
android:valueTo="72.0"
49+
android:stepSize="1.0"
50+
app:thumbColor="?attr/colorPrimary"
51+
app:trackColorActive="?attr/colorPrimary"
52+
app:trackColorInactive="?attr/colorSurfaceVariant"
53+
app:thumbRadius="6dp"
54+
app:haloRadius="0dp" /> <!-- Remove halo for compactness -->
7055
</LinearLayout>
7156

72-
</com.google.android.material.card.MaterialCardView>
57+
<com.google.android.material.switchmaterial.SwitchMaterial
58+
android:id="@+id/item_switch"
59+
android:layout_width="wrap_content"
60+
android:layout_height="wrap_content"
61+
android:saveEnabled="false"
62+
app:useMaterialThemeColors="true" />
63+
64+
</LinearLayout>

0 commit comments

Comments
 (0)