Skip to content

Commit c6165b6

Browse files
author
betapix
committed
fixed theme colour & bottom nav bar
1 parent 4dca0de commit c6165b6

20 files changed

Lines changed: 428 additions & 135 deletions

File tree

README.md

Lines changed: 38 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
1-
# 🎬 PluginStream - Ultimate Multi-Source Entertainment Hub
1+
# 🎬 PluginStream Max - Ultimate Multi-Source Entertainment Hub
22

33
<p align="center">
4-
<a href="https://am-abdulmueed.vercel.app/pluginstream">
4+
<a href="https://pluginstream.pages.dev">
55
<img src="https://img.shields.io/badge/DOWNLOAD-APK_NOW-blue?style=for-the-badge&logo=android&logoColor=white" alt="Download APK" height="40">
66
</a>
77
</p>
88

99
<p align="center">
10-
<img src="https://img.shields.io/github/downloads/maxrave-dev/SimpMusic/total?style=flat-square&color=blue&label=TOTAL%20DOWNLOADS" />
11-
<img src="https://img.shields.io/badge/Version-2.0.7-green?style=flat-square" />
12-
<img src="https://img.shields.io/badge/Platform-Android-orange?style=flat-square" />
10+
<img src="https://img.shields.io/badge/Version-5.0.0-green?style=flat-square&logo=github" />
11+
<img src="https://img.shields.io/badge/Platform-Android-orange?style=flat-square&logo=android" />
12+
<img src="https://img.shields.io/badge/Security-0%2F95%20Clean-brightgreen?style=flat-square&logo=virustotal" />
1313
</p>
1414

15-
PluginStream is a high-performance, lightweight Android application designed to aggregate premium streaming platforms into a single interface. The app acts as a powerful "Shell"—it does not host any content itself but uses a sophisticated **Plugin & Extension architecture** to provide access to movies, series, and live TV from across the web.
15+
**PluginStream Max** is a high-performance, lightweight Android application designed to aggregate premium streaming platforms into a single interface. It uses a sophisticated **Plugin & Extension architecture** to provide ad-free access to movies, series, and live TV.
1616

1717
---
1818

1919
## 📑 Table of Contents
2020
- [Screenshots](#-screenshots)
2121
- [Key Features](#-key-features)
2222
- [Download & Installation](#-download--installation)
23-
- [Quick Start Guide](#-quick-start-guide)
24-
- [Configuration](#-configuration)
23+
- [Security Verification](#-security-first)
2524
- [Performance Metrics](#-performance-metrics)
26-
- [Legal Disclaimer](#-legal-disclaimer)
2725
- [Contact & Support](#-contact--support)
2826

2927
---
@@ -34,61 +32,51 @@ PluginStream is a high-performance, lightweight Android application designed to
3432
<img src="images/1.png" width="180" />
3533
<img src="images/2.png" width="180" />
3634
<img src="images/3.png" width="180" />
37-
<img src="images/4.png" width="180" />
35+
<img src="images/4.png" width="180" />
3836
<img src="images/5.png" width="180" />
39-
<img src="images/6.png" width="180" />
40-
<img src="images/7.png" width="180" />
41-
<img src="images/8.png" width="180" />
42-
<img src="images/9.png" width="180" />
4337
</p>
38+
4439
---
4540

46-
## 🚀 Key Features
41+
## 🚀 Key Features (v5.0.0 Updates)
4742

48-
### 1. Multi-Repository Support
49-
* **Modular Architecture:** Similar to PluginStream, you can add any external repository (.json) to unlock thousands of streaming sources.
50-
* **Auto-Sync:** Extensions update automatically in the background to ensure links remain active and working.
51-
* **Custom Repos:** Add unlimited repositories from community developers and creators.
43+
### 1. The "Max" Powerhouse
44+
* **Unified Library:** Merges all major streaming providers into one single, powerful section.
45+
* **Auto-Sync:** Extensions update automatically to ensure working links 24/7.
5246

53-
### 2. Global Content Reach
54-
* **Regional Specialists:** Dedicated support for Hindi, Urdu, and English sources (Bollyflix, VegaMovies, 9kMovies, etc.).
55-
* **Premium Mirrors:** Access mirrors for major platforms like Netflix, Disney+, and Prime Video.
56-
* **Live Sports & IPTV:** Integrated support for IPTV playlists and live sports sources (CricHD, DaddyLive).
47+
### 2. Zero-Ad Experience
48+
* **Built-in AdBlocker:** Advanced filtering that strips intrusive ads and trackers from 3rd-party links.
49+
* **No Login Required:** Privacy-first approach. No account, no tracking.
5750

5851
### 3. Advanced Media Player
59-
* **Subtitle Integration:** Built-in OpenSubtitles support and custom local subtitle files.
60-
* **Dynamic Quality:** Choose from 360p to 4K resolutions.
61-
* **Offline Mode:** Download movies and episodes directly to your device.
62-
* **Chromecast Support:** Stream to smart TVs and Cast devices seamlessly.
63-
64-
### 4. Zero-Ad Experience
65-
* **Built-in AdBlocker:** Advanced filtering that strips intrusive ads and trackers from 3rd-party stream links.
66-
* **Real-time Threat Detection:** Identifies and blocks malicious redirects.
52+
* **Dynamic Quality:** Stream from 360p to 4K resolutions.
53+
* **Subtitle Support:** Built-in OpenSubtitles integration.
54+
* **Chromecast:** Stream to Smart TVs seamlessly.
6755

6856
---
6957

7058
## 📥 Download & Installation
7159

72-
### Stable Release
73-
You can download the latest stable version (70MB) from the official distribution page:
60+
👉 **[Download PluginStream Max APK](https://pluginstream.pages.dev)**
7461

75-
👉 **[Download PluginStream APK](https://am-abdulmueed.vercel.app/pluginstream)**
62+
### Quick Steps:
63+
1. **Enable Unknown Sources** in your Android settings.
64+
2. **Download & Install** the APK from our official site.
65+
3. **Join Telegram** for the latest plugins and updates.
7666

77-
### Installation Steps
78-
1. **Enable Unknown Sources:** `Settings``Security``Unknown Sources`
79-
2. **Download the APK:** From the link above.
80-
3. **Install & Launch:** Open the file and tap `Install`.
67+
---
8168

8269
---
70+
### 🛡️ Security First
71+
This APK is verified and 100% safe to install. No malware, no trackers.
8372

84-
## ⚙️ Configuration
73+
<p align="center">
74+
<a href="https://www.virustotal.com/gui/file/2caee46a7d76043619269983bbdaf50626c76eeba0e18cc36fcc9b78f5ec87c5/detection">
75+
<img src="https://img.shields.io/badge/VirusTotal-Clean%200%2F95-brightgreen?style=for-the-badge&logo=virustotal" alt="VirusTotal Report">
76+
</a>
77+
</p>
8578

86-
### Advanced Settings
87-
| Setting | Description | Default |
88-
|---------|-------------|---------|
89-
| **Auto-Update** | Enable automatic extension updates | ON |
90-
| **Quality Preference** | Default streaming quality | 720p |
91-
| **Cache Size** | Maximum cache storage | 2GB |
79+
---
9280

9381
---
9482

@@ -98,19 +86,14 @@ You can download the latest stable version (70MB) from the official distribution
9886
| **App Size** | ~70MB |
9987
| **Startup Time** | <2 seconds |
10088
| **Memory Usage** | 80-150MB |
101-
| **Battery Impact** | ~3% per hour streaming |
102-
103-
---
104-
105-
## ⚖️ Legal Disclaimer
106-
**PluginStream** is a functional "Aggregator" and "Parser." It does not host, store, or distribute any media files or copyrighted content. Users are solely responsible for complying with their local copyright laws.
89+
| **Status** | Stable ✅ |
10790

10891
---
10992

11093
## 📫 Contact & Support
94+
* **Official Website:** [pluginstream.pages.dev](https://pluginstream.pages.dev)
95+
* **Telegram Channel:** [@pluginstreamofficial](https://t.me/pluginstreamofficial)
96+
* **Support Group:** [PluginStream Support](https://t.me/pluginstreamsupport)
11197
* **Developer:** Abdul Mueed
112-
* **Portfolio:** [am-abdulmueed.vercel.app](https://am-abdulmueed.vercel.app)
113-
* **GitHub Issues:** [Report Bugs](https://github.com/am-abdulmueed/pluginstream/issues)
114-
* **Telegram Community:** [Join Group](https://t.me/pluginstream)
11598

116-
**Made with ❤️ by Abdul Mueed** | **Last Updated:** March 2026
99+
**Made with ❤️ by Abdul Mueed** | **Last Updated:** April 2026

app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt

Lines changed: 106 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@ import androidx.appcompat.app.AppCompatActivity
3131
import androidx.cardview.widget.CardView
3232
import androidx.core.content.edit
3333
import androidx.core.net.toUri
34+
import androidx.core.view.ViewCompat
35+
import androidx.core.view.WindowInsetsCompat
3436
import androidx.core.view.children
3537
import androidx.core.view.get
3638
import androidx.core.view.isGone
3739
import androidx.core.view.isInvisible
3840
import androidx.core.view.isVisible
3941
import androidx.core.view.marginStart
42+
import androidx.core.view.updateLayoutParams
4043
import androidx.fragment.app.FragmentActivity
4144
import androidx.lifecycle.ViewModelProvider
4245
import androidx.navigation.NavController
@@ -274,6 +277,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa
274277

275278
const val LAST_INSTAGRAM_DIALOG_SHOW_TIME = "last_instagram_dialog_show_time"
276279
const val INSTAGRAM_ALREADY_FOLLOWED = "instagram_already_followed"
280+
const val LAST_TELEGRAM_DIALOG_SHOW_TIME = "last_telegram_dialog_show_time"
281+
const val TELEGRAM_ALREADY_JOINED = "telegram_already_joined"
277282

278283
/**
279284
* @return true if the str has launched an app task (be it successful or not)
@@ -501,6 +506,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa
501506
R.id.navigation_player
502507
).contains(destination.id)
503508

509+
binding?.bannerContainer?.isVisible =
510+
!listOf(
511+
R.id.navigation_results_phone,
512+
R.id.navigation_results_tv,
513+
R.id.navigation_player
514+
).contains(destination.id)
515+
504516
val isNavVisible = listOf(
505517
R.id.navigation_home,
506518
R.id.navigation_search,
@@ -560,6 +572,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa
560572
binding?.apply {
561573
navRailView.isVisible = isNavVisible && isLandscape()
562574
navView.isVisible = isNavVisible && !isLandscape()
575+
navViewContainer.isVisible = isNavVisible && !isLandscape()
563576
navHostFragment.apply {
564577
val marginPx = resources.getDimensionPixelSize(R.dimen.nav_rail_view_width)
565578
layoutParams = (navHostFragment.layoutParams as ViewGroup.MarginLayoutParams).apply {
@@ -1192,23 +1205,31 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa
11921205
val currentTime = System.currentTimeMillis()
11931206

11941207
// Show only if setup is done and not already followed
1195-
if (!hasDoneSetup || alreadyFollowed) return
1208+
if (!hasDoneSetup || alreadyFollowed) {
1209+
showTelegramFollowDialog()
1210+
return
1211+
}
11961212

11971213
// Show only if it's a new day (at least 24 hours passed) or first time (lastShowTime == 0)
11981214
val oneDayMillis = 24 * 60 * 60 * 1000
1199-
if (lastShowTime != 0L && currentTime - lastShowTime < oneDayMillis) return
1215+
if (lastShowTime != 0L && currentTime - lastShowTime < oneDayMillis) {
1216+
showTelegramFollowDialog()
1217+
return
1218+
}
12001219

12011220
val dialog = Dialog(this, R.style.DialogHalfFullscreen)
12021221
val dialogView = layoutInflater.inflate(R.layout.instagram_follow_dialog, null)
12031222
dialog.setContentView(dialogView)
12041223
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
12051224

12061225
val followButton = dialogView.findViewById<com.google.android.material.button.MaterialButton>(R.id.follow_button)
1207-
val dismissButton = dialogView.findViewById<com.google.android.material.button.MaterialButton>(R.id.dismiss_button)
1226+
12081227
val alreadyFollowedCheckbox = dialogView.findViewById<CheckBox>(R.id.already_followed_checkbox)
12091228

1210-
dismissButton.setOnClickListener {
1211-
dialog.dismiss()
1229+
1230+
1231+
dialog.setOnDismissListener {
1232+
showTelegramFollowDialog()
12121233
}
12131234

12141235
// Only show checkbox if it's NOT the first time (lastShowTime != 0)
@@ -1246,6 +1267,65 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa
12461267
dialog.show()
12471268
}
12481269

1270+
private fun showTelegramFollowDialog() {
1271+
val alreadyJoined = getKey(TELEGRAM_ALREADY_JOINED, false) ?: false
1272+
val lastShowTime = getKey<Long>(LAST_TELEGRAM_DIALOG_SHOW_TIME) ?: 0L
1273+
val hasDoneSetup = getKey(HAS_DONE_SETUP_KEY, false) ?: false
1274+
val currentTime = System.currentTimeMillis()
1275+
1276+
// Show only if setup is done and not already joined
1277+
if (!hasDoneSetup || alreadyJoined) return
1278+
1279+
// Show only if it's a new day (at least 24 hours passed) or first time (lastShowTime == 0)
1280+
val oneDayMillis = 24 * 60 * 60 * 1000
1281+
if (lastShowTime != 0L && currentTime - lastShowTime < oneDayMillis) return
1282+
1283+
val dialog = Dialog(this, R.style.DialogHalfFullscreen)
1284+
val dialogView = layoutInflater.inflate(R.layout.telegram_follow_dialog, null)
1285+
dialog.setContentView(dialogView)
1286+
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
1287+
1288+
val joinButton = dialogView.findViewById<com.google.android.material.button.MaterialButton>(R.id.join_button)
1289+
1290+
val alreadyJoinedCheckbox = dialogView.findViewById<CheckBox>(R.id.already_joined_checkbox)
1291+
1292+
1293+
1294+
// Only show checkbox if it's NOT the first time (lastShowTime != 0)
1295+
if (lastShowTime != 0L) {
1296+
alreadyJoinedCheckbox.isVisible = true
1297+
}
1298+
1299+
alreadyJoinedCheckbox.setOnCheckedChangeListener { _, isChecked ->
1300+
if (isChecked) {
1301+
joinButton.text = "DISMISS"
1302+
} else {
1303+
joinButton.text = "JOIN NOW"
1304+
}
1305+
}
1306+
1307+
joinButton.setOnClickListener {
1308+
if (alreadyJoinedCheckbox.isChecked) {
1309+
setKey(TELEGRAM_ALREADY_JOINED, true)
1310+
dialog.dismiss()
1311+
} else {
1312+
// Open Telegram URL
1313+
try {
1314+
val intent = Intent(Intent.ACTION_VIEW, "https://t.me/pluginstreamofficial".toUri())
1315+
startActivity(intent)
1316+
} catch (e: Exception) {
1317+
logError(e)
1318+
}
1319+
dialog.dismiss()
1320+
}
1321+
}
1322+
1323+
// Update last show time
1324+
setKey(LAST_TELEGRAM_DIALOG_SHOW_TIME, currentTime)
1325+
1326+
dialog.show()
1327+
}
1328+
12491329
@Suppress("DEPRECATION_ERROR")
12501330
override fun onCreate(savedInstanceState: Bundle?) {
12511331
app.initClient(this)
@@ -1348,12 +1428,22 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa
13481428
}
13491429

13501430
binding?.apply {
1351-
fixSystemBarsPadding(
1352-
navView,
1353-
heightResId = R.dimen.nav_view_height,
1354-
padTop = false,
1355-
overlayCutout = false
1356-
)
1431+
// Apply insets to the container for floating bottom nav
1432+
ViewCompat.setOnApplyWindowInsetsListener(navViewContainer) { view, windowInsets ->
1433+
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
1434+
1435+
// Set the container margins based on system bars for modern floating look
1436+
// This removes the "extra space" below the card while keeping it floating above the system bars
1437+
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
1438+
// Margin should be system bar height + our desired floating margin (12dp)
1439+
// If system bar height is 0 (gesture nav), it will still have 12dp margin
1440+
bottomMargin = insets.bottom + 12.toPx
1441+
leftMargin = insets.left + 24.toPx
1442+
rightMargin = insets.right + 24.toPx
1443+
}
1444+
1445+
WindowInsetsCompat.CONSUMED
1446+
}
13571447

13581448
fixSystemBarsPadding(
13591449
navRailView,
@@ -1734,20 +1824,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa
17341824
val navController = navHostFragment.navController
17351825

17361826
navController.addOnDestinationChangedListener { _: NavController, navDestination: NavDestination, bundle: Bundle? ->
1827+
updateNavBar(navDestination)
17371828
// Intercept search and add a query
17381829
if (navDestination.id == R.id.navigation_setup_language || navDestination.id == R.id.navigation_setup_extensions || navDestination.id == R.id.navigation_setup_provider_languages || navDestination.id == R.id.navigation_setup_media || navDestination.id == R.id.navigation_setup_layout) {
1739-
binding?.bannerContainer?.visibility = View.GONE
1740-
binding?.navView?.visibility = View.GONE
1741-
binding?.navRailView?.visibility = View.GONE
1742-
} else {
1743-
binding?.bannerContainer?.visibility = View.VISIBLE
1744-
if (isLayout(PHONE)) {
1745-
binding?.navView?.visibility = View.VISIBLE
1746-
binding?.navRailView?.visibility = View.GONE
1747-
} else {
1748-
binding?.navView?.visibility = View.GONE
1749-
binding?.navRailView?.visibility = View.VISIBLE
1750-
}
1830+
binding?.bannerContainer?.isVisible = false
1831+
binding?.navView?.isVisible = false
1832+
binding?.navViewContainer?.isVisible = false
1833+
binding?.navRailView?.isVisible = false
17511834
}
17521835
if (navDestination.matchDestination(R.id.navigation_search) && !nextSearchQuery.isNullOrBlank()) {
17531836
bundle?.apply {

0 commit comments

Comments
 (0)