Skip to content

Commit c150638

Browse files
committed
docs: expand README with comprehensive API usage, slots, and troubleshooting
Improve project entry point with structured API tables, configuration examples, and platform-specific troubleshooting guides to support developer onboarding.
1 parent d63779e commit c150638

1 file changed

Lines changed: 262 additions & 25 deletions

File tree

README.md

Lines changed: 262 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,38 @@
11
# GeoQibla
22

3-
[Documentation](https://shahidzbi4213.github.io/GeoQibla/) | [GitHub](https://github.com/Shahidzbi4213/GeoQibla)
3+
<p align="center">
4+
<img src="docs/assets/geoqibla-logo.svg" alt="GeoQibla logo" width="180" />
5+
</p>
46

5-
GeoQibla is a Kotlin Multiplatform Compose library for showing Qibla direction in Android and iOS apps. It provides a ready-made shared screen, a headless controller for custom UI, and styling, string, and slot APIs for product-specific presentation.
7+
<p align="center">
8+
Kotlin Multiplatform Compose Qibla direction UI for Android and iOS apps.
9+
</p>
10+
11+
<p align="center">
12+
13+
[![Maven Central](https://img.shields.io/maven-central/v/io.github.shahidzbi4213/geoqibla?label=Maven%20Central&color=096B58)](https://central.sonatype.com/artifact/io.github.shahidzbi4213/geoqibla)
14+
[![GitHub Release](https://img.shields.io/github/v/release/Shahidzbi4213/GeoQibla?color=096B58)](https://github.com/Shahidzbi4213/GeoQibla/releases)
15+
[![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-0A7C66)](https://shahidzbi4213.github.io/GeoQibla/)
16+
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
17+
</p>
18+
19+
GeoQibla gives Compose Multiplatform apps a ready-made Qibla compass screen, a headless controller for custom UI, and public styling, localization, and slot APIs for product-specific presentation.
620

721
Current version: `0.0.1`
822

9-
## Install
23+
## Features
1024

11-
Add the dependency in your KMP module's `commonMain` source set:
25+
- **Compose-first**: Drop in `GeoQiblaScreen` for a complete adaptive Qibla flow.
26+
- **Cross-platform**: Shared Kotlin API for Android and iOS.
27+
- **Headless control**: Build custom screens from `QiblaController.state`.
28+
- **Location and sensor state**: Permission, settings, calibration, tilt, heading accuracy, and error handling.
29+
- **Configurable behavior**: Alignment thresholds, smoothing, update interval, magnetic limits, haptics, and `onAligned`.
30+
- **Custom presentation**: `QiblaStyle`, `QiblaStrings`, and `QiblaSlots` for theming, RTL text, and region replacement.
31+
- **Reusable components**: Public compass dial, status panel, and state message composables.
32+
33+
## Installation
34+
35+
Add the dependency to your KMP module's `commonMain` source set:
1236

1337
```kotlin
1438
kotlin {
@@ -20,7 +44,49 @@ kotlin {
2044
}
2145
```
2246

23-
## Quick Usage
47+
### Using Version Catalog
48+
49+
Add to `gradle/libs.versions.toml`:
50+
51+
```toml
52+
[versions]
53+
geoqibla = "0.0.1"
54+
55+
[libraries]
56+
geoqibla = { module = "io.github.shahidzbi4213:geoqibla", version.ref = "geoqibla" }
57+
```
58+
59+
Then use it from your KMP module:
60+
61+
```kotlin
62+
kotlin {
63+
sourceSets {
64+
commonMain.dependencies {
65+
implementation(libs.geoqibla)
66+
}
67+
}
68+
}
69+
```
70+
71+
### Platform Setup
72+
73+
**Android** - GeoQibla declares foreground location permissions in its Android library manifest:
74+
75+
```xml
76+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
77+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
78+
```
79+
80+
Your app still needs to handle Play policy disclosures and test heading behavior on a physical device.
81+
82+
**iOS** - Add location usage text to `Info.plist`:
83+
84+
```xml
85+
<key>NSLocationWhenInUseUsageDescription</key>
86+
<string>GeoQibla uses your location to calculate the direction of the Qibla.</string>
87+
```
88+
89+
## Quick Start
2490

2591
```kotlin
2692
import androidx.compose.runtime.Composable
@@ -37,46 +103,217 @@ fun QiblaRoute() {
37103
}
38104
```
39105

40-
## API Overview
106+
`GeoQiblaScreen` starts the controller while it is in composition and stops it when it leaves composition.
107+
108+
## Platform Support
109+
110+
| Platform | Minimum | Runtime services |
111+
| --- | --- | --- |
112+
| Android | API 26+ | `LocationManager`, `SensorManager`, foreground location permission |
113+
| iOS | App target supported by your KMP app | `CoreLocation`, heading updates, when-in-use location permission |
114+
115+
Compass behavior should be verified on physical devices. Emulators and simulators are useful for layout and permission-state checks, but not final heading accuracy.
41116

42-
- `GeoQiblaScreen`: ready-made adaptive screen with compass, status, messages, and action buttons.
43-
- `rememberQiblaController`: creates a controller backed by Android or iOS platform services.
44-
- `QiblaController.state`: `StateFlow<QiblaState>` for custom UIs.
45-
- `QiblaConfig`: alignment thresholds, smoothing, location interval, tilt and magnetic limits, haptics, and `onAligned`.
46-
- `QiblaStyle`, `QiblaStrings`, and `QiblaSlots`: styling, localization, RTL behavior, and region replacement.
47-
- `QiblaCompassDial`, `QiblaStatusPanel`, and `QiblaStateMessage`: reusable public UI components.
117+
## Configuration
118+
119+
Pass `QiblaConfig` to `rememberQiblaController()`:
120+
121+
```kotlin
122+
val controller = rememberQiblaController(
123+
config = QiblaConfig(
124+
nearDegrees = 10f,
125+
alignedDegrees = 3f,
126+
stableAlignedDurationMillis = 750L,
127+
smoothingFactor = 0.15f,
128+
locationUpdateIntervalMillis = 1_000L,
129+
tiltLimitDegrees = 55f,
130+
magneticFieldMinMicrotesla = 25f,
131+
magneticFieldMaxMicrotesla = 65f,
132+
hapticsEnabled = true,
133+
onAligned = {
134+
// Called after stable alignment.
135+
},
136+
),
137+
)
138+
```
139+
140+
| Property | Default | Description |
141+
| --- | --- | --- |
142+
| `nearDegrees` | `10f` | Direction difference treated as near Qibla. |
143+
| `alignedDegrees` | `3f` | Direction difference treated as aligned. |
144+
| `stableAlignedDurationMillis` | `750L` | Delay before `onAligned` fires. |
145+
| `smoothingFactor` | `0.15f` | Compass heading smoothing, from `0f` to `1f`. |
146+
| `locationUpdateIntervalMillis` | `1_000L` | Location update interval. |
147+
| `tiltLimitDegrees` | `55f` | Tilt threshold before the UI warns the user. |
148+
| `magneticFieldMinMicrotesla` | `25f` | Low magnetic-field calibration threshold. |
149+
| `magneticFieldMaxMicrotesla` | `65f` | High magnetic-field calibration threshold. |
150+
| `hapticsEnabled` | `true` | Enables alignment haptics where supported. |
151+
| `onAligned` | `null` | Callback after stable alignment. |
48152

49153
## Custom UI
50154

155+
Use the controller directly when you want your own screen:
156+
51157
```kotlin
52-
val controller = rememberQiblaController()
53-
val state by controller.state.collectAsState()
158+
import androidx.compose.runtime.Composable
159+
import androidx.compose.runtime.collectAsState
160+
import androidx.compose.runtime.getValue
161+
import com.shahid.tech.qibla.QiblaUiState
162+
import com.shahid.tech.qibla.rememberQiblaController
163+
164+
@Composable
165+
fun CustomQiblaRoute() {
166+
val controller = rememberQiblaController()
167+
val state by controller.state.collectAsState()
168+
169+
when (state.uiState) {
170+
QiblaUiState.ALIGNED -> {
171+
// Render aligned state.
172+
}
173+
QiblaUiState.PERMISSION_REQUIRED -> {
174+
// Show a permission prompt and call controller.requestPermission().
175+
}
176+
else -> {
177+
// Render compass from state.compass and state.location.
178+
}
179+
}
180+
}
54181
```
55182

56-
Use `state.uiState`, `state.compass`, and `state.location` to render your own flow while delegating platform location and heading behavior to GeoQibla.
183+
The state model exposes:
57184

58-
## Platform Notes
185+
- `state.uiState`: high-level UI state such as `LOCATING`, `READY`, `NEAR_QIBLA`, or `ALIGNED`.
186+
- `state.compass`: Qibla bearing, current azimuth, direction delta, distance, tilt, magnetic field, and alignment flags.
187+
- `state.location`: location access, current fix, location-service availability, and address label.
188+
- `state.sensorAccuracy`: heading sensor quality.
189+
- `state.orientationSource`: rotation vector, accelerometer/magnetometer, platform heading, or none.
190+
- `state.errorMessage`: optional platform or controller error text.
59191

60-
Android apps should use minSdk 26 or newer. GeoQibla declares foreground location permissions in its Android library manifest, requests runtime location permission from the default UI, and uses Android framework location and sensor APIs.
192+
## Styling and Slots
61193

62-
iOS apps should include location usage text in `Info.plist`:
194+
Use `QiblaStyle`, `QiblaStrings`, and `QiblaSlots` to customize the default screen without replacing its behavior:
63195

64-
```xml
65-
<key>NSLocationWhenInUseUsageDescription</key>
66-
<string>GeoQibla uses your location to calculate the direction of the Qibla.</string>
196+
```kotlin
197+
import androidx.compose.ui.graphics.Color
198+
import com.shahid.tech.qibla.GeoQiblaScreen
199+
import com.shahid.tech.qibla.QiblaColors
200+
import com.shahid.tech.qibla.QiblaSlots
201+
import com.shahid.tech.qibla.QiblaStrings
202+
import com.shahid.tech.qibla.QiblaStyle
203+
204+
GeoQiblaScreen(
205+
controller = controller,
206+
style = QiblaStyle.default().copy(
207+
colors = QiblaColors(
208+
primary = Color(0xFF096B58),
209+
qibla = Color(0xFF0A7C66),
210+
),
211+
),
212+
strings = QiblaStrings.arabic(),
213+
slots = QiblaSlots(
214+
topBar = { state ->
215+
// Custom header.
216+
},
217+
actionButtons = { state ->
218+
// Custom action row.
219+
},
220+
),
221+
)
67222
```
68223

69-
Compass behavior should be verified on physical devices. Emulators and simulators are useful for layout and permission-state checks, but not final heading accuracy.
224+
## Public Components
70225

71-
## Documentation
226+
The default screen is built from reusable public components:
227+
228+
| Component | Purpose |
229+
| --- | --- |
230+
| `GeoQiblaScreen` | Complete adaptive screen with lifecycle handling. |
231+
| `QiblaCompassDial` | Compass dial and Qibla pointer. |
232+
| `QiblaStatusPanel` | Bearing, distance, sensor, and location status rows. |
233+
| `QiblaStateMessage` | State-specific message and supporting copy. |
234+
235+
## API Reference
236+
237+
### QiblaController
238+
239+
```kotlin
240+
interface QiblaController {
241+
val state: StateFlow<QiblaState>
242+
243+
fun start()
244+
fun stop()
245+
fun retryLocation()
246+
fun requestPermission()
247+
fun openLocationSettings()
248+
fun openAppSettings()
249+
fun dismissCalibration()
250+
}
251+
```
252+
253+
### QiblaState
72254

73-
The full docs site is configured with MkDocs Material and published to GitHub Pages:
255+
```kotlin
256+
data class QiblaState(
257+
val uiState: QiblaUiState = QiblaUiState.IDLE,
258+
val compass: QiblaCompassState = QiblaCompassState(),
259+
val location: QiblaLocationState = QiblaLocationState(),
260+
val sensorAccuracy: QiblaSensorAccuracy = QiblaSensorAccuracy.UNKNOWN,
261+
val orientationSource: QiblaOrientationSource = QiblaOrientationSource.NONE,
262+
val isStarted: Boolean = false,
263+
val errorMessage: String? = null,
264+
)
265+
```
266+
267+
## Troubleshooting
268+
269+
### Compass points the wrong way
270+
271+
Test on a physical device, keep the device flat, and confirm location permission is granted. Emulators and simulators do not provide reliable final heading accuracy.
272+
273+
### Permission state is stuck
274+
275+
Call `controller.requestPermission()` from a user action. If the user permanently denies permission, call `controller.openAppSettings()`.
276+
277+
### Location is disabled
278+
279+
Use `controller.openLocationSettings()` from your UI. The default screen already shows the relevant action for this state.
280+
281+
### Calibration warning appears
282+
283+
Ask the user to move away from magnetic interference and follow the device calibration motion. You can provide a custom calibration region with `QiblaSlots.calibrationSheet`.
284+
285+
## Documentation
74286

75287
- [Getting started](https://shahidzbi4213.github.io/GeoQibla/getting-started/installation/)
76288
- [Configuration](https://shahidzbi4213.github.io/GeoQibla/getting-started/configuration/)
77289
- [Custom UI](https://shahidzbi4213.github.io/GeoQibla/guides/custom-ui/)
290+
- [Platform behavior](https://shahidzbi4213.github.io/GeoQibla/guides/platform-behavior/)
78291
- [Troubleshooting](https://shahidzbi4213.github.io/GeoQibla/troubleshooting/)
79292

293+
## Contributing
294+
295+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for local commands, documentation rules, and pull request expectations.
296+
297+
## Support
298+
299+
If GeoQibla helps your app, star the repository and open issues with platform details, device model, OS version, GeoQibla version, and reproduction steps.
300+
80301
## License
81302

82-
Apache 2.0.
303+
```
304+
Apache License 2.0
305+
306+
Copyright 2026 Shahid Iqbal
307+
308+
Licensed under the Apache License, Version 2.0 (the "License");
309+
you may not use this file except in compliance with the License.
310+
You may obtain a copy of the License at
311+
312+
https://www.apache.org/licenses/LICENSE-2.0
313+
314+
Unless required by applicable law or agreed to in writing, software
315+
distributed under the License is distributed on an "AS IS" BASIS,
316+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
317+
See the License for the specific language governing permissions and
318+
limitations under the License.
319+
```

0 commit comments

Comments
 (0)