Skip to content

Fix permissions formatting logging 9989925042154523083#115

Closed
harrydbarnes wants to merge 15 commits intomainfrom
fix-permissions-formatting-logging-9989925042154523083
Closed

Fix permissions formatting logging 9989925042154523083#115
harrydbarnes wants to merge 15 commits intomainfrom
fix-permissions-formatting-logging-9989925042154523083

Conversation

@harrydbarnes
Copy link
Owner

No description provided.

google-labs-jules bot and others added 15 commits January 20, 2026 07:02
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
- Implemented permission result handling in MainActivity to refresh data or show feedback.
- Replaced hardcoded SimpleDateFormat with DateUtils in CalendarCard to respect user time format preference.
- Added TODO in MainViewModel regarding hardcoded news category.
- Replaced e.printStackTrace() with Log.e() in repositories for better error tracking.
- Added TAG constants to repositories.
- Implemented permission result handling in MainActivity.
- Replaced hardcoded date format with DateUtils in CalendarCard.
- Re-implemented dynamic news category selection in MainViewModel.
- Added isLoading state to MainViewModel.
- Replaced e.printStackTrace() with Log.e() in repositories.
- Updated repositories to return Boolean success/failure status.
- Implemented transactional replaceAll in ArticleDao/NewsRepository to prevent data loss.
- Implemented retry logic in WidgetUpdateWorker based on refresh success.
- Created missing colors.xml to fix build failure.
- Implemented settings navigation in HomeScreen.
- Implemented permission result handling in MainActivity.
- Replaced hardcoded date format with DateUtils in CalendarCard.
- Re-implemented dynamic news category selection in MainViewModel.
- Added isLoading state to MainViewModel.
- Fixed combine function signature in MainViewModel to handle 8 flows.
- Replaced e.printStackTrace() with Log.e() in repositories.
- Updated repositories to return Boolean success/failure status.
- Implemented transactional replaceAll in ArticleDao/NewsRepository to prevent data loss.
- Implemented retry logic in WidgetUpdateWorker based on refresh success.
- Created missing colors.xml to fix build failure.
- Implemented settings navigation in HomeScreen.
…Repository.kt

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
- Implemented permission result handling in MainActivity.
- Replaced hardcoded date format with DateUtils in CalendarCard.
- Re-implemented dynamic news category selection in MainViewModel.
- Added isLoading state to MainViewModel.
- Fixed combine function signature in MainViewModel to handle 8 flows.
- Replaced e.printStackTrace() with Log.e() in repositories.
- Updated repositories to return Boolean success/failure status.
- Implemented transactional replaceAll in ArticleDao/NewsRepository to prevent data loss.
- Implemented retry logic in WidgetUpdateWorker based on refresh success.
- Created missing colors.xml to fix build failure.
- Implemented settings navigation in HomeScreen.
- Fixed syntax error in CalendarRepository.
- Implemented permission result handling in MainActivity.
- Replaced hardcoded date format with DateUtils in CalendarCard.
- Re-implemented dynamic news category selection in MainViewModel.
- Added isLoading state to MainViewModel.
- Refactored MainViewModel combine logic to use chained calls for type safety.
- Replaced e.printStackTrace() with Log.e() in repositories and DayAheadWidget.
- Updated repositories to return Boolean success/failure status.
- Implemented transactional replaceAll in ArticleDao/NewsRepository.
- Implemented retry logic in WidgetUpdateWorker.
- Created missing colors.xml to fix build failure.
- Implemented settings navigation in HomeScreen.
- Fixed CalendarRepository syntax error and extracted magic number.
- Added @JvmStatic to AppUtils for Java interop.
- Extracted Hilt versions in build.gradle.
- Added null/blank title filtering in NewsRepository.
- Implemented permission result handling in MainActivity.
- Replaced hardcoded date format with DateUtils in CalendarCard.
- Re-implemented dynamic news category selection in MainViewModel.
- Added isLoading state to MainViewModel.
- Refactored MainViewModel combine logic to use chained calls for type safety.
- Replaced e.printStackTrace() with Log.e() in repositories and DayAheadWidget.
- Updated repositories to return Boolean success/failure status.
- Implemented transactional replaceAll in ArticleDao/NewsRepository.
- Implemented retry logic in WidgetUpdateWorker.
- Created missing colors.xml to fix build failure.
- Implemented settings navigation in HomeScreen.
- Fixed CalendarRepository syntax error and extracted magic number.
- Added @JvmStatic to AppUtils for Java interop.
- Extracted Hilt versions in build.gradle.
- Added null/blank title filtering in NewsRepository.
- Implemented location fetching in MainActivity and updated MainViewModel.
- Updated Geocoder usage for API 33+.
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @harrydbarnes, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a comprehensive modernization of the Android application's architecture and UI. By migrating to Jetpack Compose, integrating Hilt for dependency injection, and implementing a robust data layer with Room and the Repository pattern, the project now adheres to contemporary Android development standards. These changes aim to enhance the application's scalability, maintainability, and overall developer experience, setting a strong foundation for future feature development.

Highlights

  • UI Modernization to Jetpack Compose: The application's user interface has been completely rewritten from traditional XML layouts and RecyclerView to Jetpack Compose. This involved removing numerous XML layout files and Java adapter classes, replacing them with new Kotlin composable functions and screens.
  • Architectural Refactoring with Hilt and Room: A significant architectural overhaul has been implemented, introducing Hilt for dependency injection and the Room Persistence Library for local data caching. This establishes a robust Repository pattern, separating data sources and business logic from the UI layer, improving maintainability and testability.
  • Kotlin Conversion and Coroutines Adoption: Many core Java files, including MainActivity, MainViewModel, and data models, have been converted to Kotlin. The project now extensively uses Kotlin Coroutines and Flow for asynchronous operations, leading to more concise and efficient code for data handling.
  • Enhanced Widget Update Mechanism: The DayAheadWidget and its associated WidgetUpdateWorker have been updated to leverage the new Hilt-injected repositories and Room database for fetching and caching data, simplifying the background update logic and ensuring consistency with the main application's data flow.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is an impressive and large-scale refactoring of the application. You've successfully migrated from a traditional View-based architecture to a modern one using Jetpack Compose, Kotlin, Hilt for dependency injection, and a repository pattern with Room for data persistence. The new architecture is much cleaner, more maintainable, and follows current Android best practices. I have a couple of suggestions to further improve the code, one related to a potential race condition and another for architectural consistency.

Comment on lines +171 to 198
private suspend fun fetchLocationName(lat: Double, lon: Double) {
if (Geocoder.isPresent()) {
withContext(Dispatchers.IO) {
try {
val geocoder = Geocoder(context, java.util.Locale.getDefault())
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
geocoder.getFromLocation(lat, lon, 1) { addresses ->
if (addresses.isNotEmpty()) {
val address = addresses[0]
val name = address.locality ?: address.subAdminArea ?: "Unknown Location"
_locationName.value = name
}
}
} else {
@Suppress("DEPRECATION")
val addresses = geocoder.getFromLocation(lat, lon, 1)
if (!addresses.isNullOrEmpty()) {
val address = addresses[0]
val name = address.locality ?: address.subAdminArea ?: "Unknown Location"
_locationName.value = name
}
}
} catch (e: Exception) {
_locationName.value = "Unknown Location"
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There's a potential race condition in fetchLocationName. The withContext(Dispatchers.IO) block will complete before the asynchronous geocoder.getFromLocation callback is executed on Android Tiramisu (API 33) and above. This can lead to the UI not updating with the correct location name in time because the coroutine job will finish prematurely.

To fix this, you should wrap the callback-based API in a coroutine builder like suspendCancellableCoroutine to make it a truly suspending call that waits for the callback to complete.

Comment on lines +21 to +71
@Inject
lateinit var weatherDao: WeatherDao

@Inject
lateinit var gson: Gson

override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
val pendingResult = goAsync()

CoroutineScope(Dispatchers.IO).launch {
try {
val weatherEntity = weatherDao.getWeather()
val summary = context.getSharedPreferences(AppConstants.PREFS_NAME, Context.MODE_PRIVATE)
.getString(AppConstants.KEY_SUMMARY_CACHE, context.getString(R.string.widget_default_summary))

for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId, weatherEntity?.json, summary, gson)
}
} catch (e: Exception) {
android.util.Log.e("DayAheadWidget", "Error in onUpdate", e)
} finally {
pendingResult.finish()
}
}
}

private fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
weatherJson: String?,
summary: String?,
gson: Gson
) {
val views = RemoteViews(context.packageName, R.layout.widget_day_ahead)
views.setTextViewText(R.id.widget_summary, summary)

if (weatherJson != null) {
try {
val weather = gson.fromJson(weatherJson, WeatherResponse::class.java)
val current = weather.current
views.setTextViewText(R.id.widget_temp, "%.0f°".format(current.temperature))
views.setImageViewResource(R.id.widget_weather_icon, AppUtils.getWeatherIconResource(current.weatherCode))
} catch (e: Exception) {
android.util.Log.e("DayAheadWidget", "Error parsing weather JSON", e)
}
}

appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This class can be simplified by adhering to the repository pattern you've established elsewhere. By injecting WeatherRepository instead of WeatherDao and Gson, you can remove the data-access and parsing logic from this UI component, making it cleaner and more consistent with the rest of your architecture.

    @Inject
    lateinit var weatherRepository: WeatherRepository

    override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
        val pendingResult = goAsync()

        CoroutineScope(Dispatchers.IO).launch {
            try {
                // Fetch parsed weather data from the repository
                val weather = weatherRepository.weatherData.first()
                val summary = context.getSharedPreferences(AppConstants.PREFS_NAME, Context.MODE_PRIVATE)
                    .getString(AppConstants.KEY_SUMMARY_CACHE, context.getString(R.string.widget_default_summary))

                for (appWidgetId in appWidgetIds) {
                    updateAppWidget(context, appWidgetManager, appWidgetId, weather, summary)
                }
            } catch (e: Exception) {
                android.util.Log.e("DayAheadWidget", "Error in onUpdate", e)
            } finally {
                pendingResult.finish()
            }
        }
    }

    private fun updateAppWidget(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetId: Int,
        weather: WeatherResponse?,
        summary: String?
    ) {
        val views = RemoteViews(context.packageName, R.layout.widget_day_ahead)
        views.setTextViewText(R.id.widget_summary, summary)

        if (weather != null) {
            try {
                val current = weather.current
                views.setTextViewText(R.id.widget_temp, "%.0f°".format(current.temperature))
                views.setImageViewResource(R.id.widget_weather_icon, AppUtils.getWeatherIconResource(current.weatherCode))
            } catch (e: Exception) {
                android.util.Log.e("DayAheadWidget", "Error processing weather data", e)
            }
        }

        appWidgetManager.updateAppWidget(appWidgetId, views)
    }

@harrydbarnes harrydbarnes deleted the fix-permissions-formatting-logging-9989925042154523083 branch January 23, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant