Skip to content

Commit 9d1a22a

Browse files
AkaneTan123Duo3
andcommitted
Omni: Finishing touches on compass feature
Signed-off-by: AkaneTan <[email protected]> Co-authored-by: 123Duo3 <[email protected]>
1 parent 7f33022 commit 9d1a22a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1962
-102
lines changed

.gitignore

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
1+
# Gradle files
2+
.gradle/
3+
build/
4+
5+
# Local configuration file (sdk path, etc)
6+
local.properties
7+
8+
# Log/OS Files
9+
*.log
10+
11+
# Android Studio generated files and folders
12+
captures/
13+
.externalNativeBuild/
14+
.cxx/
15+
*.apk
16+
output.json
17+
18+
# IntelliJ
119
*.iml
2-
.gradle
3-
/local.properties
4-
/.idea/caches
5-
/.idea/libraries
6-
/.idea/modules.xml
7-
/.idea/workspace.xml
8-
/.idea/navEditor.xml
9-
/.idea/assetWizardSettings.xml
20+
.idea/
21+
misc.xml
22+
deploymentTargetDropDown.xml
23+
render.experimental.xml
24+
25+
# Keystore files
26+
*.jks
27+
*.keystore
28+
29+
# Google Services (e.g. APIs or Firebase)
30+
google-services.json
31+
32+
# Android Profiling
33+
*.hprof
34+
35+
#macOS
1036
.DS_Store
11-
/build
12-
/captures
13-
.externalNativeBuild
14-
.cxx
15-
local.properties

.idea/deploymentTargetSelector.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/icon.svg

Lines changed: 1 addition & 0 deletions
Loading

.idea/misc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Omni
2+
![GitHub](https://img.shields.io/github/license/AkaneFoundation/Omni?style=flat-square&logoColor=white&labelColor=black&color=white)
3+
![GitHub tag (with filter)](https://img.shields.io/github/v/tag/AkaneFoundation/Omni?style=flat-square&logoColor=white&labelColor=black&color=white)
4+
[![Static Badge](https://img.shields.io/badge/Telegram-Content?style=flat-square&logo=telegram&logoColor=black&color=white)](https://t.me/AkaneDev)
5+
6+
## Features
7+
- Up-to-date material 3 design
8+
- Lightweight, no spyware or bloat
9+
- Compass with latitude & longitude
10+
- Gradienter (WIP)
11+
- Barometer (WIP)
12+
- Coin flipper (WIP)
13+
- Ruler (WIP)
14+
- Strength-adjustable flashlight (WIP)
15+
16+
## Installation
17+
You can download the latest stable version of the app from [GitHub releases](https://github.com/AkaneFoundation/Omni/releases/latest).
18+
19+
## Building
20+
To build this app, you will need the latest beta version of [Android Studio](https://developer.android.com/studio) and fast network environment.
21+
22+
## License
23+
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](https://github.com/AkaneFoundation/Omni/blob/master/LICENSE) file for details.
24+
25+
## Notice
26+
- For bug reporting: [Telegram](https://t.me/AkaneDev)

app/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ android {
99
namespace = "uk.akane.omni"
1010
compileSdk = 34
1111

12+
androidResources {
13+
generateLocaleConfig = true
14+
}
15+
16+
buildFeatures {
17+
buildConfig = true
18+
}
19+
1220
defaultConfig {
1321
applicationId = "uk.akane.omni"
1422
minSdk = 26
@@ -70,6 +78,8 @@ dependencies {
7078
implementation(libs.material)
7179
implementation(libs.androidx.activity)
7280
implementation(libs.androidx.constraintlayout)
81+
implementation(libs.androidx.preference.ktx)
82+
implementation(libs.androidx.core.splashscreen)
7383
testImplementation(libs.junit)
7484
androidTestImplementation(libs.androidx.junit)
7585
androidTestImplementation(libs.androidx.espresso.core)

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
66
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
7-
<uses-feature android:name="android.hardware.sensor.accelerometer" />
8-
<uses-feature android:name="android.hardware.sensor.compass" />
9-
<uses-feature android:name="android.hardware.sensor.gyroscope" />
7+
<uses-permission android:name="android.permission.INTERNET" />
108

119
<application
1210
android:name=".Omni"

app/src/main/java/uk/akane/omni/Omni.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ import com.google.android.material.color.DynamicColors
66
class Omni : Application() {
77
override fun onCreate() {
88
super.onCreate()
9-
DynamicColors.applyToActivitiesIfAvailable(this)
9+
// DynamicColors.applyToActivitiesIfAvailable(this)
1010
}
1111
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,192 @@
11
package uk.akane.omni.logic
22

3+
import android.animation.TimeInterpolator
4+
import android.content.Context
5+
import android.content.pm.PackageManager
6+
import android.content.res.Configuration
7+
import android.graphics.Color
8+
import android.graphics.Interpolator
9+
import android.hardware.SensorManager
10+
import androidx.core.graphics.Insets
11+
import android.os.Build
12+
import android.os.Looper
13+
import android.os.StrictMode
14+
import android.view.Display
15+
import android.view.View
16+
import android.widget.TextView
17+
import androidx.activity.ComponentActivity
18+
import androidx.activity.SystemBarStyle
19+
import androidx.activity.enableEdgeToEdge
20+
import androidx.core.content.ContextCompat
21+
import androidx.core.view.ViewCompat
22+
import androidx.core.view.WindowInsetsCompat
23+
import androidx.core.view.children
24+
import com.google.android.material.appbar.AppBarLayout
25+
import com.google.android.material.appbar.CollapsingToolbarLayout
26+
import uk.akane.omni.BuildConfig
27+
28+
@Suppress("NOTHING_TO_INLINE")
29+
inline fun Context.doIHavePermission(perm: String) =
30+
ContextCompat.checkSelfPermission(this, perm) == PackageManager.PERMISSION_GRANTED
31+
32+
val Context.isLocationPermissionGranted: Boolean
33+
get() = doIHavePermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
34+
|| doIHavePermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
35+
36+
fun ComponentActivity.enableEdgeToEdgeProperly() {
37+
if ((resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) ==
38+
Configuration.UI_MODE_NIGHT_YES
39+
) {
40+
enableEdgeToEdge(navigationBarStyle = SystemBarStyle.dark(Color.TRANSPARENT))
41+
} else {
42+
val darkScrim = Color.argb(0x80, 0x1b, 0x1b, 0x1b)
43+
enableEdgeToEdge(navigationBarStyle = SystemBarStyle.light(Color.TRANSPARENT, darkScrim))
44+
}
45+
}
46+
47+
fun View.fadOutAnimation(
48+
duration: Long = 300,
49+
visibility: Int = View.INVISIBLE,
50+
interpolator: TimeInterpolator,
51+
completion: (() -> Unit)? = null
52+
) {
53+
animate()
54+
.alpha(0f)
55+
.setDuration(duration)
56+
.setInterpolator(interpolator)
57+
.withEndAction {
58+
this.visibility = visibility
59+
completion?.let {
60+
it()
61+
}
62+
}
63+
}
64+
65+
fun View.fadInAnimation(
66+
duration: Long = 300,
67+
completion: (() -> Unit)? = null,
68+
interpolator: TimeInterpolator
69+
) {
70+
alpha = 0f
71+
visibility = View.VISIBLE
72+
animate()
73+
.alpha(1f)
74+
.setDuration(duration)
75+
.setInterpolator(interpolator)
76+
.withEndAction {
77+
completion?.let {
78+
it()
79+
}
80+
}
81+
}
82+
83+
fun TextView.setTextAnimation(
84+
text: CharSequence?,
85+
duration: Long = 300,
86+
completion: (() -> Unit)? = null,
87+
skipAnimation: Boolean = false,
88+
fadeInInterpolator: TimeInterpolator,
89+
fadeOutInterpolator: TimeInterpolator
90+
) {
91+
if (skipAnimation) {
92+
this.text = text
93+
completion?.let { it() }
94+
} else if (this.text != text) {
95+
fadOutAnimation(duration, View.INVISIBLE, fadeOutInterpolator) {
96+
this.text = text
97+
fadInAnimation(duration, interpolator = fadeInInterpolator, completion = {
98+
completion?.let {
99+
it()
100+
}
101+
})
102+
}
103+
} else {
104+
completion?.let { it() }
105+
}
106+
}
107+
108+
fun SensorManager.checkSensorAvailability(sensorType: Int): Boolean {
109+
return getDefaultSensor(sensorType) != null
110+
}
111+
112+
// the whole point of this function is to do literally nothing at all (but without impacting
113+
// performance) in release builds and ignore StrictMode violations in debug builds
114+
inline fun <reified T> allowDiskAccessInStrictMode(doIt: () -> T): T {
115+
return if (BuildConfig.DEBUG) {
116+
if (Looper.getMainLooper() != Looper.myLooper()) throw IllegalStateException()
117+
val policy = StrictMode.allowThreadDiskReads()
118+
try {
119+
StrictMode.allowThreadDiskWrites()
120+
doIt()
121+
} finally {
122+
StrictMode.setThreadPolicy(policy)
123+
}
124+
} else doIt()
125+
}
126+
127+
fun View.enableEdgeToEdgePaddingListener(ime: Boolean = false, top: Boolean = false,
128+
extra: ((Insets) -> Unit)? = null) {
129+
if (fitsSystemWindows) throw IllegalArgumentException("must have fitsSystemWindows disabled")
130+
if (this is AppBarLayout) {
131+
if (ime) throw IllegalArgumentException("AppBarLayout must have ime flag disabled")
132+
// AppBarLayout fitsSystemWindows does not handle left/right for a good reason, it has
133+
// to be applied to children to look good; we rewrite fitsSystemWindows in a way mostly specific
134+
// to Gramophone to support shortEdges displayCutout
135+
val collapsingToolbarLayout = children.find { it is CollapsingToolbarLayout } as CollapsingToolbarLayout?
136+
collapsingToolbarLayout?.let {
137+
// The CollapsingToolbarLayout mustn't consume insets, we handle padding here anyway
138+
ViewCompat.setOnApplyWindowInsetsListener(it) { _, insets -> insets }
139+
}
140+
val expandedTitleMarginStart = collapsingToolbarLayout?.expandedTitleMarginStart
141+
val expandedTitleMarginEnd = collapsingToolbarLayout?.expandedTitleMarginEnd
142+
ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
143+
val cutoutAndBars = insets.getInsets(
144+
WindowInsetsCompat.Type.systemBars()
145+
or WindowInsetsCompat.Type.displayCutout()
146+
)
147+
(v as AppBarLayout).children.forEach {
148+
if (it is CollapsingToolbarLayout) {
149+
val es = expandedTitleMarginStart!! + if (it.layoutDirection
150+
== View.LAYOUT_DIRECTION_LTR) cutoutAndBars.left else cutoutAndBars.right
151+
if (es != it.expandedTitleMarginStart) it.expandedTitleMarginStart = es
152+
val ee = expandedTitleMarginEnd!! + if (it.layoutDirection
153+
== View.LAYOUT_DIRECTION_RTL) cutoutAndBars.left else cutoutAndBars.right
154+
if (ee != it.expandedTitleMarginEnd) it.expandedTitleMarginEnd = ee
155+
}
156+
it.setPadding(cutoutAndBars.left, 0, cutoutAndBars.right, 0)
157+
}
158+
v.setPadding(0, cutoutAndBars.top, 0, 0)
159+
val i = insets.getInsetsIgnoringVisibility(WindowInsetsCompat.Type.systemBars()
160+
or WindowInsetsCompat.Type.displayCutout())
161+
extra?.invoke(cutoutAndBars)
162+
return@setOnApplyWindowInsetsListener WindowInsetsCompat.Builder(insets)
163+
.setInsets(WindowInsetsCompat.Type.systemBars()
164+
or WindowInsetsCompat.Type.displayCutout(), Insets.of(cutoutAndBars.left, 0, cutoutAndBars.right, cutoutAndBars.bottom))
165+
.setInsetsIgnoringVisibility(WindowInsetsCompat.Type.systemBars()
166+
or WindowInsetsCompat.Type.displayCutout(), Insets.of(i.left, 0, i.right, i.bottom))
167+
.build()
168+
}
169+
} else {
170+
val pl = paddingLeft
171+
val pt = paddingTop
172+
val pr = paddingRight
173+
val pb = paddingBottom
174+
ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
175+
val mask = WindowInsetsCompat.Type.systemBars() or
176+
WindowInsetsCompat.Type.displayCutout() or
177+
if (ime) WindowInsetsCompat.Type.ime() else 0
178+
val i = insets.getInsets(mask)
179+
v.setPadding(pl + i.left, pt + (if (top) i.top else 0), pr + i.right,
180+
pb + i.bottom)
181+
extra?.invoke(i)
182+
return@setOnApplyWindowInsetsListener WindowInsetsCompat.Builder(insets)
183+
.setInsets(mask, Insets.NONE)
184+
.setInsetsIgnoringVisibility(mask, Insets.NONE)
185+
.build()
186+
}
187+
}
188+
}
189+
190+
@Suppress("NOTHING_TO_INLINE")
191+
inline fun Int.dpToPx(context: Context): Int =
192+
(this.toFloat() * context.resources.displayMetrics.density).toInt()

0 commit comments

Comments
 (0)