From 6bb0ae6e2dd7f296995bb95c8e3203a193b0277e Mon Sep 17 00:00:00 2001 From: iso53 <102249575+ISO53@users.noreply.github.com> Date: Sat, 31 Jan 2026 15:33:07 +0300 Subject: [PATCH 1/5] automated github and playstore release AI wrote this workflow not me, hope it works --- .github/workflows/release.yml | 57 +++++++++++++++++++++++++++++++++++ app/build.gradle.kts | 6 ++++ 2 files changed, 63 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2598810 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,57 @@ +name: Android Release + +on: + push: + branches: [ main ] + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Decode keystore + run: | + echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > keystore.jks + + - name: Build APK + AAB + run: | + chmod +x gradlew + ./gradlew assembleRelease bundleRelease + + - name: Extract versionName + id: version + run: | + VERSION=$(grep versionName app/build.gradle.kts | cut -d '"' -f2) + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ steps.version.outputs.version }} + name: v${{ steps.version.outputs.version }} + generate_release_notes: true + files: | + app/build/outputs/apk/release/*.apk + + - name: Upload AAB to Play Store (internal) + uses: r0adkll/upload-google-play@v1 + with: + serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }} + packageName: io.github.iso53.nothingcompass + releaseFiles: app/build/outputs/bundle/release/*.aab + track: internal + status: completed diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5f90128..990d32f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -54,4 +54,10 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) +} + +tasks.register("printVersionName") { + doLast { + println(android.defaultConfig.versionName) + } } \ No newline at end of file From 093af6fa6099e73e54151661cefa082f0bc28ca5 Mon Sep 17 00:00:00 2001 From: iso53 <102249575+ISO53@users.noreply.github.com> Date: Sun, 1 Feb 2026 15:47:01 +0300 Subject: [PATCH 2/5] added open source licenses --- app/build.gradle.kts | 2 ++ .../io/github/iso53/nothingcompass/OptionsActivity.java | 9 +++------ gradle/libs.versions.toml | 2 ++ settings.gradle.kts | 7 +++++++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 990d32f..d4cc9ca 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,6 @@ plugins { alias(libs.plugins.android.application) + id("com.google.android.gms.oss-licenses-plugin") } android { @@ -54,6 +55,7 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) + implementation(libs.play.services.oss.licenses) } tasks.register("printVersionName") { diff --git a/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java b/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java index 46249bd..39182fe 100644 --- a/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java +++ b/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java @@ -17,6 +17,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import java.util.ArrayList; @@ -28,10 +29,6 @@ public class OptionsActivity extends AppCompatActivity { - private static void onClick(View v) { - // TODO: Show OSS licenses - } - @Override protected void onCreate(Bundle savedInstanceState) { // Apply theme before super.onCreate @@ -96,8 +93,8 @@ private void setupRecyclerView() { items.add(new OptionItem(getString(R.string.category_support))); items.add(new OptionItem(getString(R.string.item_license), null, R.drawable.ic_license, v -> openUrl("https://github.com/iso53/Nothing-Compass/blob/main/LICENSE.md"))); - items.add(new OptionItem(getString(R.string.item_third_party_licenses), null, - R.drawable.ic_verified, OptionsActivity::onClick)); + items.add(new OptionItem(getString(R.string.item_third_party_licenses), null, R.drawable.ic_verified, + v -> startActivity(new Intent(this, OssLicensesMenuActivity.class)))); items.add(new OptionItem(getString(R.string.item_manage_permission), null, R.drawable.ic_permission, v -> openAppSettings())); items.add(new OptionItem(getString(R.string.item_help_feedback), null, R.drawable.ic_help, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 599acea..b6667f7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ material = "1.13.0" activity = "1.12.2" constraintlayout = "2.2.1" fragment = "1.8.9" +playServicesOssLicenses = "17.3.0" sdpAndroid = "1.1.1" sspAndroid = "1.1.1" viewpager2 = "1.0.0" @@ -23,6 +24,7 @@ material = { group = "com.google.android.material", name = "material", version.r activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" } +play-services-oss-licenses = { module = "com.google.android.gms:play-services-oss-licenses", version.ref = "playServicesOssLicenses" } sdp-android = { module = "com.intuit.sdp:sdp-android", version.ref = "sdpAndroid" } ssp-android = { module = "com.intuit.ssp:ssp-android", version.ref = "sspAndroid" } viewpager2 = { group = "androidx.viewpager2", name = "viewpager2", version.ref = "viewpager2" } diff --git a/settings.gradle.kts b/settings.gradle.kts index d5c07fc..2927cc6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,6 +9,13 @@ pluginManagement { } mavenCentral() gradlePluginPortal() + resolutionStrategy { + eachPlugin { + if (requested.id.id == "com.google.android.gms.oss-licenses-plugin") { + useModule("com.google.android.gms:oss-licenses-plugin:0.10.10") + } + } + } } } dependencyResolutionManagement { From b055811d6cb0e87e2af64f790133db142d984a88 Mon Sep 17 00:00:00 2001 From: iso53 <102249575+ISO53@users.noreply.github.com> Date: Sun, 1 Feb 2026 15:47:14 +0300 Subject: [PATCH 3/5] file name fix --- .../java/io/github/iso53/nothingcompass/OptionsActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java b/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java index 39182fe..faddc86 100644 --- a/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java +++ b/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java @@ -92,7 +92,7 @@ private void setupRecyclerView() { // Category: Support items.add(new OptionItem(getString(R.string.category_support))); items.add(new OptionItem(getString(R.string.item_license), null, R.drawable.ic_license, - v -> openUrl("https://github.com/iso53/Nothing-Compass/blob/main/LICENSE.md"))); + v -> openUrl("https://github.com/iso53/Nothing-Compass/blob/main/LICENSE"))); items.add(new OptionItem(getString(R.string.item_third_party_licenses), null, R.drawable.ic_verified, v -> startActivity(new Intent(this, OssLicensesMenuActivity.class)))); items.add(new OptionItem(getString(R.string.item_manage_permission), null, From 24505df86b9b99dddf740060327402456c2b6d07 Mon Sep 17 00:00:00 2001 From: iso53 <102249575+ISO53@users.noreply.github.com> Date: Sun, 1 Feb 2026 15:47:36 +0300 Subject: [PATCH 4/5] reformatting --- .../iso53/nothingcompass/OptionsActivity.java | 115 ++++++++---------- 1 file changed, 48 insertions(+), 67 deletions(-) diff --git a/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java b/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java index faddc86..07f1eab 100644 --- a/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java +++ b/app/src/main/java/io/github/iso53/nothingcompass/OptionsActivity.java @@ -5,7 +5,6 @@ import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; -import android.view.View; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; @@ -43,14 +42,14 @@ protected void onCreate(Bundle savedInstanceState) { ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.optionsToolbar), (v, insets) -> { - Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); - v.setPadding(systemBars.left, systemBars.top, systemBars.right, 0); - return insets; - }); + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding(systemBars.left, systemBars.top, systemBars.right, 0); + return insets; + }); // Handle bottom padding for RecyclerView to avoid navigation bar overlap ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.optionsRecyclerView), (v, - insets) -> { + insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), systemBars.bottom + v.getPaddingBottom()); @@ -59,8 +58,7 @@ protected void onCreate(Bundle savedInstanceState) { // Setup Toolbar findViewById(R.id.optionsToolbar).setOnClickListener(v -> finish()); - ((androidx.appcompat.widget.Toolbar) findViewById(R.id.optionsToolbar)) - .setNavigationOnClickListener(v -> finish()); + ((androidx.appcompat.widget.Toolbar) findViewById(R.id.optionsToolbar)).setNavigationOnClickListener(v -> finish()); setupRecyclerView(); } @@ -75,8 +73,8 @@ private void setupRecyclerView() { items.add(new OptionItem(getString(R.string.category_preferences))); items.add(new OptionItem(getString(R.string.item_theme), null, R.drawable.ic_settings, v -> showThemeSelectionDialog())); - items.add(new OptionItem(getString(R.string.item_haptic_feedback), null, R.drawable.ic_vibration, - v -> showHapticFeedbackSelectionDialog())); + items.add(new OptionItem(getString(R.string.item_haptic_feedback), null, + R.drawable.ic_vibration, v -> showHapticFeedbackSelectionDialog())); // Category: App items.add(new OptionItem(getString(R.string.category_app))); @@ -93,12 +91,13 @@ private void setupRecyclerView() { items.add(new OptionItem(getString(R.string.category_support))); items.add(new OptionItem(getString(R.string.item_license), null, R.drawable.ic_license, v -> openUrl("https://github.com/iso53/Nothing-Compass/blob/main/LICENSE"))); - items.add(new OptionItem(getString(R.string.item_third_party_licenses), null, R.drawable.ic_verified, - v -> startActivity(new Intent(this, OssLicensesMenuActivity.class)))); + items.add(new OptionItem(getString(R.string.item_third_party_licenses), null, + R.drawable.ic_verified, v -> startActivity(new Intent(this, + OssLicensesMenuActivity.class)))); items.add(new OptionItem(getString(R.string.item_manage_permission), null, R.drawable.ic_permission, v -> openAppSettings())); - items.add(new OptionItem(getString(R.string.item_help_feedback), null, R.drawable.ic_help, - v -> sendFeedbackEmail())); + items.add(new OptionItem(getString(R.string.item_help_feedback), null, R.drawable.ic_help + , v -> sendFeedbackEmail())); items.add(new OptionItem(getString(R.string.item_rate_app), null, R.drawable.ic_rate, v -> openPlayStore())); @@ -107,63 +106,50 @@ private void setupRecyclerView() { } private void showThemeSelectionDialog() { - String[] themes = { - getString(R.string.theme_light), - getString(R.string.theme_dark), - getString(R.string.theme_system) - }; + String[] themes = {getString(R.string.theme_light), getString(R.string.theme_dark), + getString(R.string.theme_system)}; SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); int currentTheme = prefs.getInt(PreferenceConstants.THEME, AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); int checkedItem = 2; // Default to System - if (currentTheme == AppCompatDelegate.MODE_NIGHT_NO) - checkedItem = 0; - else if (currentTheme == AppCompatDelegate.MODE_NIGHT_YES) - checkedItem = 1; - - new MaterialAlertDialogBuilder(this) - .setTitle(R.string.item_theme) - .setSingleChoiceItems(themes, checkedItem, (dialog, which) -> { - int mode; - switch (which) { - case 0: - mode = AppCompatDelegate.MODE_NIGHT_NO; - break; - case 1: - mode = AppCompatDelegate.MODE_NIGHT_YES; - break; - default: - mode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM; - break; - } - prefs.edit().putInt(PreferenceConstants.THEME, mode).apply(); - AppCompatDelegate.setDefaultNightMode(mode); - dialog.dismiss(); - }) - .show(); + if (currentTheme == AppCompatDelegate.MODE_NIGHT_NO) checkedItem = 0; + else if (currentTheme == AppCompatDelegate.MODE_NIGHT_YES) checkedItem = 1; + + new MaterialAlertDialogBuilder(this).setTitle(R.string.item_theme).setSingleChoiceItems(themes, checkedItem, (dialog, which) -> { + int mode; + switch (which) { + case 0: + mode = AppCompatDelegate.MODE_NIGHT_NO; + break; + case 1: + mode = AppCompatDelegate.MODE_NIGHT_YES; + break; + default: + mode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM; + break; + } + prefs.edit().putInt(PreferenceConstants.THEME, mode).apply(); + AppCompatDelegate.setDefaultNightMode(mode); + dialog.dismiss(); + }).show(); } private void showHapticFeedbackSelectionDialog() { - String[] options = { - getString(R.string.haptic_feedback_on), - getString(R.string.haptic_feedback_off) - }; + String[] options = {getString(R.string.haptic_feedback_on), + getString(R.string.haptic_feedback_off)}; SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); boolean currentHaptic = prefs.getBoolean(PreferenceConstants.HAPTIC_FEEDBACK, true); int checkedItem = currentHaptic ? 0 : 1; - new MaterialAlertDialogBuilder(this) - .setTitle(R.string.item_haptic_feedback) - .setSingleChoiceItems(options, checkedItem, (dialog, which) -> { - boolean enabled = (which == 0); - prefs.edit().putBoolean(PreferenceConstants.HAPTIC_FEEDBACK, enabled).apply(); - dialog.dismiss(); - }) - .show(); + new MaterialAlertDialogBuilder(this).setTitle(R.string.item_haptic_feedback).setSingleChoiceItems(options, checkedItem, (dialog, which) -> { + boolean enabled = (which == 0); + prefs.edit().putBoolean(PreferenceConstants.HAPTIC_FEEDBACK, enabled).apply(); + dialog.dismiss(); + }).show(); } private void openPlayStore() { @@ -172,8 +158,8 @@ private void openPlayStore() { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName))); } catch (ActivityNotFoundException e) { - startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("https://play.google.com/store/apps/details?id=" + packageName))); + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google" + + ".com/store/apps/details?id=" + packageName))); } } @@ -196,18 +182,13 @@ private void sendFeedbackEmail() { } catch (Exception ignored) { } - String deviceInfo = "\n\n\n------------------------------" + - "\nDevice Diagnostics (Please do not delete):" + - "\nApp Version: " + appVersion + - "\nAndroid Version: " + android.os.Build.VERSION.RELEASE + " (SDK " - + android.os.Build.VERSION.SDK_INT + ")" + - "\nManufacturer: " + android.os.Build.MANUFACTURER + - "\nModel: " + android.os.Build.MODEL + - "\nProduct: " + android.os.Build.PRODUCT; + String deviceInfo = "\n\n\n------------------------------" + "\nDevice Diagnostics " + + "(Please do not delete):" + "\nApp Version: " + appVersion + "\nAndroid Version: " + + android.os.Build.VERSION.RELEASE + " (SDK " + android.os.Build.VERSION.SDK_INT + ")" + "\nManufacturer: " + android.os.Build.MANUFACTURER + "\nModel: " + android.os.Build.MODEL + "\nProduct: " + android.os.Build.PRODUCT; Intent intent = new Intent(Intent.ACTION_SENDTO); intent.setData(Uri.parse("mailto:")); - intent.putExtra(Intent.EXTRA_EMAIL, new String[] { feedbackEmail }); + intent.putExtra(Intent.EXTRA_EMAIL, new String[]{feedbackEmail}); intent.putExtra(Intent.EXTRA_SUBJECT, "Feedback/Support - Nothing Compass"); intent.putExtra(Intent.EXTRA_TEXT, deviceInfo); From 4d8be66ea8202d6e6d6a864aeb44f89cdaeb86a5 Mon Sep 17 00:00:00 2001 From: iso53 <102249575+ISO53@users.noreply.github.com> Date: Sun, 1 Feb 2026 15:54:16 +0300 Subject: [PATCH 5/5] Create PRIVACY_POLICY.md --- PRIVACY_POLICY.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 PRIVACY_POLICY.md diff --git a/PRIVACY_POLICY.md b/PRIVACY_POLICY.md new file mode 100644 index 0000000..2fc626a --- /dev/null +++ b/PRIVACY_POLICY.md @@ -0,0 +1,29 @@ +# Privacy Policy for Nothing Compass + +**Last Updated: February 1, 2026** + +Nothing Compass ("the App") is developed as an Open Source project by Yusuf İhsan Şimşek ("the Developer"). This Privacy Policy explains how information is handled within the App. + +## 1. No Data Collection +Nothing Compass is designed to respect your privacy. The App does not collect, store, or transmit any personal data or usage information to the Developer or any third party. All calculations and sensor data processing occur entirely on your device. + +## 2. Device Sensors and Location Data +- **Sensors**: The App uses your device's sensors (such as the magnetometer and accelerometer) to provide compass and inclinometer functionality. This sensor data is processed locally on your device in real-time. +- **Location**: If you enable "True North" features, the App may request access to your device's location to calculate magnetic declination. This location data is used only for calculation within the App, is processed locally, and is never uploaded, stored, or shared. + +## 3. Permissions +- **Vibrate**: Used to provide haptic feedback to enhance the user experience. This can be disabled in the App settings. + +## 4. Third-Party Services +The App may use the following third-party services which may collect information used to identify you: +- **Google Play Services**: Used for features such as In-App Reviews. Google's privacy policy applies: [Google Privacy & Terms](https://policies.google.com/privacy) +- **GitHub**: The App's source code is hosted on GitHub. If you visit the project page or report an issue, GitHub's privacy policy applies. + +## 5. User-Initiated Communication +If you choose to contact the Developer for feedback, support, or to report an issue (e.g., via email or GitHub), the information you provide—including any diagnostic information generated by the App—will only be used to address your inquiry and improve the App. + +## 6. Changes to This Privacy Policy +The Developer may update this Privacy Policy from time to time. Any changes will be posted on this page with an updated "Last Updated" date. + +## 7. Contact +If you have any questions or suggestions regarding this Privacy Policy, please contact the Developer at [ihsansimsek5335@gmail.com](mailto:ihsansimsek5335@gmail.com) or via the [GitHub repository](https://github.com/iso53/Nothing-Compass).