A digital wellbeing Android app that helps minimise distractions when you don't want them

Overview

Bundel logo
GitHub Workflow Status (branch)   Apache 2.0 license   Watch us code on Twitch   Follow us on Twitter

Bundel is a digital wellbeing Android app, helping you to focus by grouping up notifications and only releasing them in batches, at set times. This minimises context switching and improves productivity, while decreasing the impulse to continuously check your phone.

State of the project

The app is in its very early dev stages. It's likely to crash and burn at any time, it's not optimised, it is not even an MVP (minimum viable product) for what it wants to be. It's a work in progress, and you can expect continued development and fixes, horrible temporary design, and all those fun things we all get through when we're prototyping something. But it will get better! Nice things just need time.

Why this app, why open source

This project was born out of an idea Ivan Morgillo and Sebastiano Poggi had: we wanted to learn using Jetpack Compose, and maybe catch up on some other cool Android stuff. But side projects never really get completed, and at the same time, just putting the code out there wouldn't really give much insight into the how and why things are done a certain way. Open source is a great way to sharing knowledge, and this being a side project for us, that was a given. But making the sources available in and by itself isn't enough: you miss the context, get presented with a final solution to a largely unknown problem. Just think how many times you've wondered why some code you were reading was done in that way and not in another!

So, we decided we'd share the entire process. We stream ourselves, and some awesome guests, coding on the app, learning as we go, making mistakes and fixing them. We've rather unoriginally named this project Code with the Italians, as both Ivan and myself come from the country that brought you pizza (oh, and by the way, you're welcome!).

This app, Bundel, is our first in this live coding project of ours — who knows what will come next.

Code with the Italians logo

I want to watch y'all crazies code

The good news is, it's really easy to do! To keep up to date with all that's happening, you should follow @codewiththeita on Twitter. If Twitter isn't your thing — we understand! — we also make announcements on Telegram.

We live stream on Twitch and on YouTube. You can also find the whole archive of previous streams over on YouTube.

We regularly stream ourselves coding on this app. We are generally live at these times:

  • Wednesdays, at 18:30 CEST / 12:30 PM EST / 9:30 AM PST
  • Sundays, at 17:00 CEST / 11 AM EST / 8 AM PST

Dates and times may vary though, so watch out for announcements. Or, you know, add this nifty iCal subscription to your calendar. You can find some instructions here.

I want to contribute

Find the guide to contributing here

Acknowledgements

While ourselves, Ivan and Seb, are the two main authors of this app and the hosts of the streams, we need to acknowledge that we're standing on the shoulders of giants.

We need to thank all our friendly guests, each bringing their invaluable experience and patience towards our bs to the streams and app. Thank you, thank you, thank you! You folks are 💛

We also want to thank everyone that helped us behind the scenes with our oddly specific questions and doubts, saving us countless hours of swearing and hacking away at tough problems.

Lastly, we thank everyone who's following us, watching us code, donating to the cause, and spreading the word. Y'all are the reason we're doing this!

I know it says "lastly" right above this, but I feel we should also really thank the fine folks at Google Developers who have done us the honour of featuring us in their brand new DevLibrary.

License

Bundel is licensed under the Apache 2.0 license.

   Copyright 2021 the Bundel contributors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       https://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
Comments
  • Optimize DatabaseModule DI setup

    Optimize DatabaseModule DI setup

    I annotated the provideDatabase method with @Singleton annotation to avoid creating a new database instance for every injection. I also marked the DataRepository with @Singleton for similar reasons. Although DatabaseModule is installed in a singleton component, you still have to scope its bindings. See the following for more info: https://dagger.dev/hilt/components

    I replaced the provide method with constructor injection to bind the DiskImagesStorage. However, one thing to note is that the ImagesStorage from DI is never used.

    opened by ZianeA 2
  • Something is off with WEBP_LOSSLESS support

    Something is off with WEBP_LOSSLESS support

    Describe the bug App crashing after giving access to notifications

    To Reproduce Steps to reproduce the behavior:

    1. Give permissions
    2. Go back to the app

    Expected behavior I would expect to reach the main screen.

    Screenshots N.A.

    Smartphone (please complete the following information):

    • Device: S9
    • OS: Android 10

    Additional context

    java.lang.NoSuchFieldError: No static field WEBP_LOSSLESS of type Landroid/graphics/Bitmap$CompressFormat; in class Landroid/graphics/Bitmap$CompressFormat; or its superclasses (declaration of 'android.graphics.Bitmap$CompressFormat' appears in /system/framework/framework.jar)
            at dev.sebastiano.bundel.storage.DiskImagesStorage$ImageFormat.<clinit>(DiskImagesStorage.kt:109)
            at dev.sebastiano.bundel.storage.DiskImagesStorage.getCachedImageFormat(DiskImagesStorage.kt:99)
            at dev.sebastiano.bundel.storage.DiskImagesStorage.getIconFile(DiskImagesStorage.kt:59)
            at dev.sebastiano.bundel.storage.DiskImagesStorage.saveIcon(DiskImagesStorage.kt:37)
            at dev.sebastiano.bundel.storage.DiskImagesStorage.saveIconsFrom(DiskImagesStorage.kt:24)
            at dev.sebastiano.bundel.storage.RobertoRepository.saveNotification(RobertoRepository.kt:15)
            at dev.sebastiano.bundel.storage.RobertoRepository$saveNotification$1.invokeSuspend(Unknown Source:15)
            at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
            at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
            at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
            at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
            at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
            at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
            at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
            at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
            at dev.sebastiano.bundel.notifications.BundelNotificationListenerService.onListenerConnected(BundelNotificationListenerService.kt:30)
            at android.service.notification.NotificationListenerService$MyHandler.handleMessage(NotificationListenerService.java:2076)
            at android.os.Handler.dispatchMessage(Handler.java:107)
            at android.os.Looper.loop(Looper.java:237)
            at android.app.ActivityThread.main(ActivityThread.java:8167)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
    
    bug 
    opened by hamen 2
  • Crash on giving notification access

    Crash on giving notification access

    Describe the bug App crashes on giving notification access

    To Reproduce Steps to reproduce the behavior:

    1. Open project in Android Studio.
    2. Run it on Emulator API 29 or API 30
    3. Give notification access to the app on device
    4. App Crashes

    Error via logcat:

    2021-05-14 14:38:24.583 11014-11014/dev.sebastiano.bundel E/AndroidRuntime: FATAL EXCEPTION: main
        Process: dev.sebastiano.bundel, PID: 11014
        java.lang.RuntimeException: Tried to marshall a Parcel that contained Binder objects.
            at android.os.Parcel.nativeMarshall(Native Method)
            at android.os.Parcel.marshall(Parcel.java:552)
            at dev.sebastiano.bundel.storage.NotificationsCache.toByteArray(NotificationsCache.kt:53)
            at dev.sebastiano.bundel.storage.NotificationsCache.writeToFile(NotificationsCache.kt:44)
            at dev.sebastiano.bundel.storage.NotificationsCache.storeStatusBarNotification(NotificationsCache.kt:36)
            at dev.sebastiano.bundel.storage.RobertoRepository$saveNotification$2.invokeSuspend(RobertoRepository.kt:24)
    

    Expected behavior To not crash

    bug 
    opened by shipsywor 2
  • Don't auto update Kotlin version + KSP

    Don't auto update Kotlin version + KSP

    Add component selection rules rejecting any Kotlin version that does not match the version in the libs.version.toml file. The effect of this is that the Kotlin version will always require a manual version bump and will not be updated with ./gradlew versionCatalogUpdate, which is probably the safest since Compose is also tied to a specific Kotlin version.

    For KSP any version that does not match the specified Kotlin version is rejected so that the KSP and Kotlin versions should always match.

    opened by hvisser 1
  • App crashes at startup

    App crashes at startup

    Describe the bug The app crashes on startup with the following exception:

    java.lang.NullPointerException: getString(context.contentResolver, "enabled_notification_listeners") must not be null
    at dev.sebastiano.bundel.notifications.NotificationServiceHelpersKt.needsNotificationsPermission(NotificationServiceHelpers.kt:9)
    

    To Reproduce I was able to get the app to start by making the following changes:

    internal fun needsNotificationsPermission(context: Context): Boolean {
        val pkgName = context.packageName
        val enabledListeners = Settings.Secure.getString(context.contentResolver, "enabled_notification_listeners")
            ?.split(":")
        if (enabledListeners != null && enabledListeners.isEmpty()) return false
    
        return enabledListeners == null || enabledListeners
            .map { listenerPackageName -> ComponentName.unflattenFromString(listenerPackageName) }
            .none { pkgName == it?.packageName }
    }
    

    However, after the fix, I couldn't reproduce the error by simply uninstalling the app. I had to wipe the device data for the error to recur.

    Desktop (please complete the following information):

    • OS: Windows 10

    Smartphone (please complete the following information):

    • Device: Emulator
    • OS: Android API 30
    bug 
    opened by ZianeA 1
  • Add workflow to periodically check for dependency updates

    Add workflow to periodically check for dependency updates

    This adds a workflow to run ./gradlew versionCatalogUpdate and, if the catalog is updated, create a PR with the diffs. The workflow is scheduled to run once a week, and can be triggered manually too.

    The heavy lifting is in the peter-evans/create-pull-request action that will manage creating and updating the PR when changes are detected. Because during the build gradlew is also changed, that change is reverted before creating the PR.

    The PR does not give a comprehensive description of the changed dependencies, it merely produces a new branch and a diff. The created branch can be used to verify the dependency updates or do adjustments before merging, mainly serving as a reminder that updates are available.

    The initial run will update the formatting of the catalog so that will be a bit noisy :)

    opened by hvisser 0
  • Add documentation to properly run the app locally

    Add documentation to properly run the app locally

    The app requires a google-services.json to run; we need to document it and explain how users can generate it, and also how they can make do with the dummy one in build-config/ if they only need to run tests or static analysis.

    documentation 
    opened by hamen 0
  • Add Crashlytics

    Add Crashlytics

    • [x] Add basic dependency
    • [x] Disable it by default
    • [x] Provide the user with a way to enable it during the onboarding
    • [ ] Provide the user with a way to disable/enable it in the Settings screen
    In Progress 
    opened by hamen 0
  • Add Settings screen PoC

    Add Settings screen PoC

    Let's create a Settings screen to setup the navigation infrastructure in the app.

    • [ ] Create a Settings screen
    • [ ] Setup Navigation Components for Compose
    • [ ] Add a button on Main screen to navigate to Settings
    opened by hamen 0
Owner
Code with the Italians
Two Italians and their friends live code interesting stuff, then dump their code here.
Code with the Italians
A minimalist but powerful productivity timer designed to keep you focused and free of distractions.

Goodtime A minimalist but powerful productivity timer designed to keep you focused and free of distractions. Alternate between focused work sessions a

Adrian Cotfas 692 Dec 27, 2022
Money Manager app that helps you to add your daily small incomes and expenses and track them easily.

Simple Money Manager This app is a simple money manager app which helps you to add your daily small incomes and expenses and track them easily. Screen

Yash Bansal 2 Nov 21, 2021
A simple and minimal app to track how long you've been sober from anything you want.

Sobriety A simple and minimal app to track how long you've been sober from anything you want. I mostly designed this out of spite for "I Am Sober", wh

Katherine Rose 26 Nov 21, 2022
A movie application where you can search a movie that you want and see the detail of movie

MovieApp This is a simple movie application where you can search a movie that you want and see the detail of movie Technologies Hilt (Dependency Injec

Serhad Mert 5 Nov 30, 2021
Ride hailing app that helps users find drivers and take them from point A to point B.

Ride-hailing_rider_app Ride hailing app that helps users find drivers and take them from point A to point B. What I Used ? Clean Architecture : Basica

Oucif Mohammed 2 Aug 26, 2022
Android app that helps you keep track of the medical supplements you need to take and how you spend your days

Android app that helps you keep track of the medical supplements you need to take and how you spend your days, similar to a bullet journal. It also allows you to reflect on your day, week, year, etc.

Rachelle Hu 4 Nov 10, 2022
EU Digital COVID Certificate Wallet App - Android

This repository contains the source code of the EU Digital COVID Certificate Wallet App for Android.

null 57 Oct 6, 2022
An unofficial companion app for DJI's Digital FPV System.

fpv-dvca An unofficial companion app for DJI's Digital FPV System for Android devices. Plug your Android device into your Googles and watch a live fee

Matthias Urhahn 73 Dec 12, 2022
Open Super dApp - Your gateway to the new digital commons. Integrated mobile messenger, Ethereum wallet, and Web 3.0 browser built on open, decentralized, and encrypted protocols.

A fully open source, open standard, decentralized "super app" including a secure, encrypted Matrix compatible messenger based off of the Element Messenger, and an Ethereum crypto wallet and web3 browser based off of Alpha Wallet.

2Gather 6 Jul 25, 2022
Android port of Simon Tatham's Puzzles. *git replace in use* - you might want to {{ git fetch origin 'refs/replace/*:refs/replace/*' }}

This is the README accompanying the source code to Simon Tatham's puzzle collection. The collection's web site is at <https://www.chiark.greenend.org.

Chris Boyle 470 Dec 22, 2022
Xposed module which will set location where you want without effect mock location.

GPS Setter Support/Discussion: XDA thread As most of GPS spoof app not working anymore coz some are old and some are not proper implement with current

Android1500 73 Dec 28, 2022
Task Timer - An android app that helps you to keep a track of how much time you spend on each task

Task Timer - An android app that helps you to keep a track of how much time you spend on each task

Hassan Al-Shammari 1 Feb 24, 2022
Dose a Android app that reminds you medications exactly when your body needs them, building entirely using Kotlin and Jetpack Compose with MVVM + Clean Architecture

??⏰ Dose is a work-in-progress Android app that reminds you medications exactly when your body needs them, building entirely using Kotlin and Jetpack Compose with MVVM + Clean Architecture

Waseef Akhtar 195 Jan 1, 2023
A Jetpack Compose-based app to exhibit all the beautiful GLSL Fragment shaders I have ever written, where you can set them as Live Wallpaper.

?? Shader Showcase Shader Showcase is a minimal Android app made with Jetpack Compose, to showcase all the beautiful OpenGL* based Fragment shaders I

Piyush Pradeepkumar 198 Dec 28, 2022
Water tracker app helps you with daily reminder to drink water. This app is just a trial to test and improve my android development skills.

?? About Me I am a self-thaught developer learning web and android development. This app is just a trial to test and improve my android development sk

Sinan Sonmez (Chaush) 28 Dec 17, 2022
The SleepQualityTracker app - a demo app that helps you collect information about your sleep

The SleepQualityTracker app is a demo app that helps you collect information about your sleep. This app builds on the SleepQualityTracker previous made, refactoring the code to make it more efficient so it will be easier to maintain and test

Alexandre Pedro 1 Apr 1, 2022
TMDbHub - Listing movies using the TMDb API. You can filter results, view details, and save them to a collection

TMDb Hub Listing movies using the TMDb API. You can filter results, view details

David Varga 4 Dec 30, 2021