{"id":21942064,"url":"https://github.com/malekkamel/bulletin","last_synced_at":"2025-07-23T00:05:39.362Z","repository":{"id":90820834,"uuid":"228855441","full_name":"MalekKamel/Bulletin","owner":"MalekKamel","description":"An abstraction for alert messages in android.","archived":false,"fork":false,"pushed_at":"2020-01-23T09:32:32.000Z","size":13186,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-22T18:12:35.881Z","etag":null,"topics":["android","bulletin","google","java","jitpack","kotlin","messages","mobile","platform","view"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MalekKamel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-18T14:19:06.000Z","updated_at":"2021-05-30T01:42:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"935cff22-a820-493e-a530-37262f9619d8","html_url":"https://github.com/MalekKamel/Bulletin","commit_stats":null,"previous_names":["malekkamel/bulletin","shabankamell/bulletin"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/MalekKamel/Bulletin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MalekKamel%2FBulletin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MalekKamel%2FBulletin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MalekKamel%2FBulletin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MalekKamel%2FBulletin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MalekKamel","download_url":"https://codeload.github.com/MalekKamel/Bulletin/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MalekKamel%2FBulletin/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266592209,"owners_count":23953109,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","bulletin","google","java","jitpack","kotlin","messages","mobile","platform","view"],"created_at":"2024-11-29T03:16:22.639Z","updated_at":"2025-07-23T00:05:39.344Z","avatar_url":"https://github.com/MalekKamel.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n[![](https://jitpack.io/v/ShabanKamell/Bulletin.svg)](https://jitpack.io/#ShabanKamell/Bulletin)\n\nBulletin\n========\nAn abstraction for alert messages in android.\n\nMore and more you need to report bulletins (messages) to the user and you spread its code everywhere. And sometimes you ask yoursef, what if I want to avoid duplicate bulletins at the same time? what if I want to queue bulletins? what if I want to apply default configurations to each bulletin only in one place? what if I want to manage all bulletins?.....  👿 👿\n\n**Bulletin** can answer all you queustions!  🙏 🙏\n\n\u003cimg src=\"https://github.com/ShabanKamell/Bulletin/blob/master/blob/master/raw/demo.gif\" height=\"500\"\u003e\n\n\u003cimg src=\"https://github.com/ShabanKamell/Bulletin/blob/master/blob/master/raw/diagram4.png\" height=\"600\"\u003e\n\n``` kotlin\n   // ignore any Bulletin if another Bulletin is diplayed with the\n   // same content\n   BulletinConfig.duplicateStrategy = ContentDuplicateStrategy()\n   \n   // queue any BulletinSheet if another BulletinSheet is diplayed \n   // and show the next queued one after dismissing the current.\n   // the same applies to BulletinToast.\n   BulletinConfig.queueStrategies {\n       + SheetQueueStrategy()\n       + ToastQueueStrategy()\n   }\n   \n   // Will be displayed\n   showMessageSheet(\"Sheet1, after dismissing, Sheet2 will be displayed!\")\n   \n   // will be queued as we deined SheetQueueStrategy\n   showMessageSheet(\"Sheet2, after dismissing, Sheet3 will be displayed!\")\n   \n   // will be queued like Sheet2\n   showMessageSheet(\"Sheet3\")\n   \n   // Will be displayed\n   shortToast(\"Toast\")\n   \n   // will be ignored as its content is similar to the previous displayed bulletin\n   // NOTE: remember that we defined ContentDuplicateStrategy\n   shortToast(\"Toast\")\n   \n   // Will dismiss any displayed Bulletin\n   BulletinManager.dismissAll()\n```\n\n## Features\n\n- [ ] Reusable widgets.\n- [ ] Predefined APIs for displaying bulletins.\n- [ ] Fully customizable.\n- [ ] Define queue strategies.\n- [ ] Define duplicate strategies\n- [ ] Global configuration for all bulletins\n- [ ] Manage all bulletins\n\n## Installation\n\n#### Gradle:\n```groovy\nallprojects {\n    repositories {\n        ...\n        maven { url \"https://jitpack.io\" }\n    }\n}\n\ndependencies {\n        implementation 'com.github.ShabanKamell:Bulletin:x.y.z'\n}\n```\n\n(Please replace x, y and z with the latest version numbers: [![](https://jitpack.io/v/ShabanKamell/Bulletin.svg)](https://jitpack.io/#ShabanKamell/Bulletin))\n\n## Bulletins\nAny widget implements [Bulletin Interface](#bulletin-interface) is a Bulletin. There're 8 predefined widgets in the library:\n\n|         **Name**                 |                        **Description**                         |\n| -------------------------------- | ---------------------------------------------------------------|\n| **InfoDialog**                   | A concrete implementaion of `BulletinDialog`                   |\n| **RetryDialog**                  | A concrete implementaion of `BulletinDialog`                   |\n| **LoadingDialog**                | A concrete implementaion of `BulletinDialog`                   |\n| **InfoSheet**                    | A concrete implementaion of `BulletinSheet`                    |\n| **RetrySheet**                   | A concrete implementaion of `BulletinSheet`                    |\n| **StandardFlashBar**             | A concrete implementaion of `BulletinFlashBar`                 |\n| **StandardToast**                | A concrete implementaion of `BulletinToast`                    |\n| **StandardSnackbar**             | A concrete implementaion of `BulletinSnackbar`                 |\n\n## Bulletin Interface\n`Bulletin` is implemented by all widgets of the library. If you want to create your custom bulletin, you must implement this interface.\n\n``` kotlin\ninterface Bulletin {\n    val name: String\n    val content: String\n    var status: BulletinStatus\n    var duplicateStrategy: DuplicateStrategy\n    fun showBulletin(activity: FragmentActivity?)\n    fun dismiss()\n}\n```\n\n## BulletinManager\nIt's the brain of the library that's responsible for showing/hiding bulletins and managing the state of each bulletin. Take a look at [BulletinManager](https://github.com/ShabanKamell/Bulletin/blob/master/lib/src/main/java/com/sha/bulletin/BulletinManager.kt) to see all functionalities.\n\n## Alertable Interface\n\nAlertable interface contains a group of default functions that make it easy to show any predefined `Bulletin`. If you want to make all these functions available for your class, just implement it. The interface is a composite of interfaces for each bulletin. Take a look at [Alertable](https://github.com/ShabanKamell/Bulletin/blob/master/lib/src/main/java/com/sha/bulletin/Alertable.kt) to see all functionalities.\n\n``` kotlin\ninterface Alertable:\n        InfoDialogAlertable,\n        InfoSheetAlertable,\n        RetryDialogAlertable,\n        RetrySheetAlertable,\n        ToastAlertable,\n        LoadingDialogAlertable,\n        FlashBarAlertable\n```\n\nIn case you don't need all functions, you can implement any interface that Alertable inhertits.\n\n##### IMPORTANT: To use Alertable with Kotlin, you must add this to apps' Gradle:\n\n``` groovy\nandroid {\n...\n    // This configuration enables using @JvmDefault annotation with Kotlin\n    kotlinOptions {\n        jvmTarget = JavaVersion.VERSION_1_8\n        freeCompilerArgs = ['-Xjvm-default=compatibility']\n    }\n}\n```\n\n## Duplicate Strategy\nWhat if there are 2 or more netwrok responses display the same content in a dialog and you don't need to show all dialogs with the same content? OR in another words you want to ignore the dialog if there's a dialog with the same content displayed?\n\n[DuplicateStrategy](#duplicate-strategy-interface) provides the solution:\n\n``` kotlin\n  BulletinConfig.duplicateStrategy = ContentDuplicateStrategy()\n```\n\nThe previous line tells **Bulletin** to ignore the new bulletin as long as a bulletin with the same content is displayed.\n\n### Duplicate Strategy Interface:\n\n``` kotlin\ninterface DuplicateStrategy {\n    var onIgnoreStrategy: IgnoreDuplicateStrategy\n    fun shouldIgnore(bulletin: Bulletin, displayedBulletins: Set\u003cBulletin\u003e): Boolean\n}\n```\n\nBUT what happens to the ignored bulletins? see [Ignore Duplicate Strategy](#ignore-duplicate-strategy)  🤔 🤔\n\nThere are multiple predefined implementaions for `DuplicateStrategy` you can find them in the next section. However, you can define your own custom strategy.\n\n### Predefined Duplicate Strategies\n\n|         **Name**                 |                        **Description**          | **Default IgnoreDuplicateStrategy** |\n| -------------------------------- | --------------------------------------------------------------------- | ------------- |\n| **DefaultDuplicateStrategy**     | Allows any diplication                                                |   DROP        |\n| **NameDuplicateStrategy**        | Ignore if a Bulletin with the same **NAME** is displayed.             |   QUEUE       |\n| **ContentDuplicateStrategy**     | Ignore if a Bulletin with the same **CONTENT** is displayed.          |   DROP        |\n| **NameContentDuplicateStrategy** | Ignore if a Bulletin with the same **NAME \u0026 CONTENT** is displayed.   |   DROP        |\n| **SingleDuplicateStrategy**      | Display a single Bulletin at a time    .                              |   QUEUE       |\n\n\n### Ignore Duplicate Strategy\n\nIf a `Bulletin` has been ignored bucause it's a duplicate one, you can define 1 of 3 behaviors for the ignored bulletin:\n\n- [ ] Drop: The bulletin will be dropped and won't be displayed forever.\n- [ ] Queue: The bulletin will be queued, and will be displayed once it's the first bulletin in the queue.\n- [ ] Try Queue: The bulletin will be queued only if there's any [Duplicate Strategy](#duplicate-strategy) allows queuing the bulletin.\n\nThese behavioiors are defined in[IgnoreDuplicateStrategy](#ignoreDuplicateStrategy-enum).\n\n#### IgnoreDuplicateStrategy Enum\n`IgnoreDuplicateStrategy` contains the ignoring behaviors that can be defined in in [DuplicateStrategy Inteface](#duplicate-strategy-interface).\n\n``` kotlin\nenum class IgnoreDuplicateStrategy { DROP, QUEUE, TRY_QUEUE }\n```\n\n## Queue Strategy\nWhat if you need to show 2 bulletins or more in a sequntial order? In another worders, what if you want to show each bulletin after dismissing the previous one?\n\n[`QueueStrategy`](#queue-strategy-interface) interface provides a solution for queuing problem:\n\n``` kotlin\nBulletinConfig.queueStrategies { +SheetQueueStrategy() }\n```\n\n### Queue Strategy Interface:\n\n``` kotlin\ninterface QueueStrategy {\n    fun shouldQueue(bulletin: Bulletin, displayedBulletins: Set\u003cBulletin\u003e): Boolean\n}\n```\n\nThere are multiple predefined implementaions for `QueueStrategy` you can find them in the next section. However, you can define your own custom strategy.\n\n### Predefined Queue Strategies\n\n|         **Name**                 |                        **Description**                         |\n| -------------------------------- | ---------------------------------------------------------------|\n| **NoneQueueStrategy**            | Don't queue any bulletin. This is the default behavior         |\n| **AllQueueStrategy**             | Queue all bulletins                                            |\n| **DialogQueueStrategy**          | Queue if a `BulletinDialog` is displayed.                      |\n| **SheetQueueStrategy**           | Queue if a `BulletinSheet` is displayed.                       |\n| **FlashbarQueueStrategy**        | Queue if a `BulletinFlashbar` is displayed.                    |\n| **SnackbarQueueStrategy**        | Queue if a `BulletinSnackar` is displayed.                     |\n| **ToastQueueStrategy**           | Queue if a `BulletinToast` is displayed.                       |\n\n## Bulletin Status\nEach `Bulletin` has a status of 5 statuses defined in `BulletinStatus`\n\n``` kotlin\nenum class BulletinStatus {\n    PENDING,\n    DISPLAYED,\n    QUEUED,\n    IGNORED,\n    DISMISSED\n}\n```\n\n- [ ] PENDING: The bulletin is created. It's the default status.\n- [ ] DISPLAYED: The bulleitn is visible on the screen.\n- [ ] QUEUED: The bulletin is queued because 1) it's queued by a `QueueStratedy` 2) it's ignored by a `DuplicateStratedy` then queued, see [Ignore Duplicate Strategy](#ignore-duplicate-strategy).\n- [ ] IGNORED: The bulletin is ignored by a `QueueStratedy`\n- [ ] DISMISSED: The bulletin is no longer visible.\n\n## Custom Bulletins\nAs mentioned in [Bulletin Interface](#bulletin-interface), you can create your custom bulletin by implementing [Bulletin] interface. Alternatively, you can extend abstract widget like `BulletinDialog` and implement your customization. see [MyCstomLadingDialog](https://github.com/ShabanKamell/Bulletin/blob/master/sample/src/main/java/com/sha/sample/MyCustomLoadingDialog.kt)\n\n## Credit\n- [ ] Flashbar is a clone of [aritraroy/Flashbar](https://github.com/aritraroy/Flashbar)\n- [ ] Dialog style is borrowed from [andyxialm/ColorDialog](https://github.com/andyxialm/ColorDialog)\n\n## 🛡 License\n\u003cdetails\u003e\n    \u003csummary\u003e\n        click to reveal License\n    \u003c/summary\u003e\n    \n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalekkamel%2Fbulletin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmalekkamel%2Fbulletin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalekkamel%2Fbulletin/lists"}