Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
b845bb5
Implement artist profiles, remake ImageGrid. Unfinished.
apex2504 Jun 30, 2026
208cbf2
Wide font for headers to match modern branding
apex2504 Jun 30, 2026
de5dd3c
Implement following artists and following tab. Very early.
apex2504 Jul 2, 2026
3bf8ab0
Refactor scroll to top button
apex2504 Jul 2, 2026
2c27eeb
Add FRE and support blocked tags in Following
apex2504 Jul 2, 2026
03f7759
Remove one nesting layer
apex2504 Jul 2, 2026
b239ed3
Add pref for default browse tab
apex2504 Jul 2, 2026
9d8b1f9
import
apex2504 Jul 2, 2026
0d21d6a
Settings reorg and minor cleanup
apex2504 Jul 3, 2026
ad95c25
Add ability to see who you're following
apex2504 Jul 4, 2026
1b13c45
compose and M3 update
apex2504 Jul 4, 2026
5464693
Separate options in content settings
apex2504 Jul 4, 2026
16dd42f
Add option to view profiles for all tags, use user preference source …
apex2504 Jul 4, 2026
fe684cf
Disallow following and blocking simultaneously
apex2504 Jul 4, 2026
df42669
Fixes in info sheet
apex2504 Jul 4, 2026
758a59d
Update non-coro LaunchedEffects to new keyed SideEffects
apex2504 Jul 6, 2026
0f6b2cb
Fix handling pre-2012 pixiv URLs
apex2504 Jul 27, 2026
04b505a
Add SauceNAO for reverse lookups
apex2504 Aug 5, 2026
671c0ed
Add API key settings and SauceNAO nsfw toggle
apex2504 Aug 5, 2026
e70370a
Fix result count when results contain unsupported media
apex2504 Aug 5, 2026
13fa591
Update M3 (fix dropdown back crash)
apex2504 Aug 10, 2026
d7ec30f
Remove deprecated ImageGrid
apex2504 Aug 10, 2026
28a35d5
Apparently I forgot to commit this lol
apex2504 Aug 10, 2026
d046b75
Update style of no recommendation texts
apex2504 Aug 10, 2026
56673c4
Dedicated style for body medium text
apex2504 Aug 10, 2026
78b18b1
Replace remaining(?) non-usages of new label style
apex2504 Aug 10, 2026
5284a79
Ease some pain points with key and settings requirements
apex2504 Aug 10, 2026
1c7a4aa
Ease SauceNAO api key flow
apex2504 Aug 10, 2026
9ce92e5
Update settings category descriptions.
apex2504 Aug 10, 2026
9bb657e
Fix crash when no SAFE posts in artist profile, hide board link chip
apex2504 Aug 10, 2026
5b4cfca
punctuation fix
apex2504 Aug 10, 2026
5500995
Add more useful message when no safe results
apex2504 Aug 10, 2026
e3f10ad
Artist profile split view on large screens
apex2504 Aug 10, 2026
3f373e1
animate potentially explicit warning
apex2504 Aug 11, 2026
ae6356b
Add Whats New and add to About Settings with changes
apex2504 Aug 11, 2026
d21eac6
Update version
apex2504 Aug 11, 2026
f236713
Merge branch 'main' into 3.3
apex2504 Aug 11, 2026
6531aef
update privacy policy
apex2504 Aug 11, 2026
4393aa6
Add pulse effect to icons on navigation item select (#61)
flazepe Aug 16, 2026
315dc6f
Move following to breadboard-controlled api
apex2504 Aug 18, 2026
4c2d42e
update compose and m3
apex2504 Aug 18, 2026
7d10676
Update privacy policy
apex2504 Aug 18, 2026
f86f3f3
Update version
apex2504 Aug 18, 2026
0c2ee2d
Add manual dark theme preference support (#62)
flazepe Aug 23, 2026
6459f55
Improve back flow when tapping tabs
apex2504 Aug 24, 2026
858cae0
remove useless comment from testing saucenao
apex2504 Aug 24, 2026
dd0d9f2
don't remove metadata from yandere images in saucenao
apex2504 Aug 24, 2026
4d03538
refactor image metadata refetching to be more intentional
apex2504 Aug 24, 2026
cb61489
Update version
apex2504 Aug 24, 2026
6a88f6d
Support sharing images to reverse search (#63)
flazepe Aug 25, 2026
a2050bb
Fix potential crash on bad clipboard item mime type (#64)
flazepe Aug 28, 2026
78e3110
Only show profile option for artists and general tags
apex2504 Aug 28, 2026
1a83765
Get settings ready for release
apex2504 Aug 28, 2026
915e04f
Update default image action order
apex2504 Aug 28, 2026
1deac7e
Update version
apex2504 Aug 28, 2026
da412e0
update bouncyAnimationSpec to M3E values
apex2504 Aug 28, 2026
e6cf160
Correctly animate warning in saucenao results
apex2504 Aug 28, 2026
8d32f87
Default sort following by time followed, add button to change to alph…
apex2504 Aug 28, 2026
c78e270
Rename most references to "Image"
apex2504 Aug 28, 2026
66e827a
Remove extra message when sharing artist
apex2504 Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 59 additions & 17 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,109 @@
# Privacy Policy for Breadboard

**Last Updated:** 30 July 2025
**Last Updated:** 18 August 2026

This Privacy Policy describes how Breadboard ("we," "us," or "our") handles your information when you use our mobile application (the "App").

### Information We Do Not Collect
Breadboard owns the domain names breadboard.moe and fxweibo.com. Web requests to these domains use industry-standard encryption and are routed through [Cloudflare](https://www.cloudflare.com/privacypolicy/) and as such, you should consult their privacy policy in addition to ours.

We want to be clear: Breadboard is designed with your privacy in mind.
### Introduction

- **No Sale of Personal Data:** We do not sell, rent, or trade any of your personal data to third parties.
- **No Analytics or Usage Stats:** We do not collect analytics or usage statistics about how you interact with the App.
We want to be clear: the Breadboard app is designed with your privacy in mind.

**No Sale of Personal Data:** We do not sell, rent, or trade any of your personal data to third parties.

### Information We Process and Why

The core purpose of Breadboard is to help you retrieve data from external platforms. To facilitate this, the following information is used:
The core purpose of the App is to help you retrieve data from external platforms, but we also provide our own services to help facilitate this.
We will split this section into two parts for ease of understanding.

#### Information Shared by The App
- **IP Address and Web Access Logs:**
- When accessing domains owned by us, access logs containing your IP address, URL accessed, and your User-Agent will be kept for 14 days for abuse and fraud prevention.
- In some cases, this may include user-created data such as a list of 'tags' in the URL to retrieve a curated feed.

- **IP Address for External Requests:** When you use Breadboard to fetch data from an external platform, your device's IP address will be used to make these requests. This is a standard part of how the internet works. We do not store your IP address. You should consult the privacy policy of the specific external platforms you interact with through Breadboard to understand how they handle your IP address and any other data they may collect.
- **Optional API Credentials:** Breadboard allows you to optionally provide API credentials (such as API keys or tokens) for specific external platforms to enable enhanced functionality.
- **Purpose and Sharing:** These credentials will be stored on your device and will **only** be shared with the specific external platform they are intended for. These credentials will be used solely for the purpose of authenticating your requests to that platform and enabling the enhanced functionality on the platform.
- **Optional API Credentials:** The App allows you to optionally provide API credentials (such as API keys or tokens) for specific external platforms to enable enhanced functionality.
- **Purpose and Sharing:** These credentials will be stored on your device and will **only** be shared with the specific external platform they are intended for. These credentials will be used solely for the purpose of authenticating your requests to that platform and enabling enhanced functionality on the platform.
- **User Control:** You are in control of providing these credentials and can revoke them at any time through the App's settings.

#### Information Processed by External Platforms
- **IP Address:**
- When you use the App to fetch data from an external platform, your device's IP address will be used to make these requests.
- **Other User-created Data:**
- This may include search queries or aggregated data derived from your App data. Read below to learn more.

You should consult the privacy policy of the specific external platforms you interact with through the App to understand how they handle your IP address and any other data they may collect.

### Following Feed

The App offers the ability to 'Follow' artists.

- **How it Works:** Each artist is represented by a unique tag that is used to retrieve their posts. The user is able to save a list of these tags locally that can be used to build a curated feed of posts.
- **Data Sent:** When requesting or refreshing your Following feed, this list may be sent to a domain owned by us and used to retrieve relevant posts.
- **Purpose:** The sole purpose of sending this list is to retrieve a list of posts by the requested artists using their tags.
- **User Control:** You can choose not to use this functionality by not clicking the 'Follow' button on an artist profile.

When a user has an empty list of followed artists, the App will use posts the user has marked as a 'Favourite' to recommend artists to follow.
This takes place entirely on-device.

If the user chooses to follow one or more artists from the recommendations that the App provides, the resultant list of followed artists may be sent to a domain owned by us.

In some cases, some or all parts of this list may be sent to [Danbooru](https://danbooru.donmai.us/privacy) to retrieve the relevant posts by these artists. Refer to Danbooru's privacy policy to learn how they use your data.

### Post Recommendations

To enhance your experience, Breadboard offers a feature to recommend posts based on content you have previously added to your favourites within the App.
To enhance your experience, the App offers a feature to recommend posts based on content you have previously added to your favourites within the App.

- **How it Works:** When you use this feature, Breadboard sends aggregated metadata derived from your favourited posts as a search query to the relevant external platform. For example, if you have favourited several posts with specific tags or keywords, Breadboard might use these common tags or keywords to find similar content on that platform.
- **How it Works:** When you use this feature, the App sends aggregated metadata derived from your favourited posts as a search query to the relevant external platform. For example, if you have favourited several posts with specific tags or keywords, the App can use these common tags or keywords to find similar content on that platform.
- **Data Sent:** Only the aggregated metadata (like common tags, categories, or keywords) is sent to the external platform as a search query. We do not send your specific list of favourited posts or any personally identifiable information from your device to the external platform for this purpose.
- **Purpose:** The sole purpose of sending this aggregated metadata is to retrieve recommendations for similar posts from the external platform.
- **User Control:** You can choose not to use this functionality by not visiting the "Browse" page within the App. You can set the App's "Start page" setting to something other than "Browse" to prevent this feature from automatically working when you open the App.

### Search History

To improve your user experience and allow you to quickly revisit previous searches, Breadboard stores your search queries locally on your device.
To improve your user experience and allow you to quickly revisit previous searches, the App stores your search queries locally on your device.

- **How it Works:** When you perform a search within the App, the search terms you use are saved to your device's local storage.
- **User Control and Deletion:** You have full control over your search history. You can delete individual search history entries at any time within the App. You also have the option to disable the search history feature entirely through the App's settings, which will prevent any future search queries from being saved. If you disable search history, any previously saved search history will also be cleared.
- **Data Storage:** Your search history is stored only on your device. It is not transmitted to us or any third party.

### Reverse Image Search

The App provides the ability to perform a 'reverse image search', whereby the user submits an image and the App provides insight such as the artist and original source.
Reverse image search functionality is provided by [SauceNAO](https://saucenao.com/legal.html) and you should consult the SauceNAO privacy policy to learn about how your data and submitted images are handled.

### Artist Sharing

The App provides the ability to share an artist profile with other users. This is in the form of a URL that points to the breadboard.moe domain.
Refer to this document's section about Information Shared by The App to learn more about how your data is used.

### Data Export

Breadboard provides you with the functionality to export your application data to a file. This allows you to back up or transfer your information.
The App provides you with the functionality to export your application data to a file. This allows you to back up or transfer your information.

- **What is Exported:** The user has the ability to choose which data categories are exported. The categories available for export include: **App settings**, **Favourite images**, and **Search history**.
- **Sensitive Information Exclusion:** For your security, sensitive information such as API credentials you have saved within the App will **not** be included in the exported file.
- **User Responsibility:** Once you export your data to a file, that file is stored on your device or in a location you choose. The security and management of this exported file become your responsibility. Breadboard is not responsible for the exported file once it has been created and saved outside of the App.
- **User Responsibility:** Once you export your data to a file, that file is stored on your device or in a location you choose. The security and management of this exported file become your responsibility. We are not responsible for the exported file once it has been created and saved outside of the App.

### Data Security

We take reasonable measures to help protect the information we process. When you provide API credentials, they are stored locally on your device, the App's developers do not have access to these credentials, and they are only used for the purpose of making requests to the external platforms you choose to interact with.

As Breadboard does not store any personal data off-device, we do not have a process for you to request deletion of personal data. You can, however, delete any stored API credentials through the App, or clear the App's data through your device settings, which will remove all locally stored information.
As the App does not identify individual users or store data for reasons other than those that are technically necessary, we do not have a process for you to request deletion of personal data. You can, however, delete any stored API credentials through the App, or clear the App's data through your device settings, which will remove all locally stored information.

Web access logs are deleted after 14 days.

### Third-Party Services

As mentioned, Breadboard interacts with external platforms. This Privacy Policy does not apply to the practices of third parties that we do not own or control. We encourage you to review the privacy policies of any third-party services you access through Breadboard.
As mentioned, the App interacts with external platforms. This Privacy Policy does not apply to the practices of third parties that we do not own or control. We encourage you to review the privacy policies of any third-party services you access through the App.

### Changes to This Privacy Policy

We may update this Privacy Policy from time to time. You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted. The "Last Updated" date at the top of this document indicates when this Privacy Policy was last revised.

### Your Consent

By using the Breadboard app, you consent to our Privacy Policy.
By using the App, you consent to our Privacy Policy.

### Contact Us

Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ android {
applicationId "moe.apex.breadboard"
minSdk 26
targetSdk 36
versionCode 323
versionName "3.2.3"
versionCode 333
versionName "3.3.3"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down
34 changes: 33 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- android:configChanges="uiMode" is added to prevent the activity from recreating itself
during night mode change, avoiding unnecessary state resets wherever possible.

android:documentLaunchMode="intoExisting" is added to prevent the activity from stacking
on top of the current app while sharing images (if no existing instance of Breadboard was
found) on older Android versions. -->
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand All @@ -12,7 +18,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.Breadboard"
android:windowSoftInputMode="adjustResize"
android:enableOnBackInvokedCallback="true">
android:enableOnBackInvokedCallback="true"
android:configChanges="uiMode"
android:documentLaunchMode="intoExisting">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
Expand All @@ -23,13 +31,28 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:label="SauceNAO">
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name=".DeepLinkActivity"
android:taskAffinity="moe.apex.breadboard.DeepLinkActivity"
android:launchMode="singleTop"
android:exported="true"
android:theme="@style/Theme.Breadboard">

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="breadboard" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
Expand Down Expand Up @@ -118,6 +141,15 @@

<data android:pathPattern="/data/preview/.*" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="https" />
<data android:host="breadboard.moe" />
<data android:pathPrefix="/artist/" />
</intent-filter>
</activity>
<activity-alias
android:name="moe.apex.rule34.MainActivity"
Expand Down
41 changes: 36 additions & 5 deletions app/src/main/java/moe/apex/breadboard/DeepLinkActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package moe.apex.breadboard

import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Browser
Expand All @@ -25,8 +26,10 @@ import coil3.gif.AnimatedImageDecoder
import coil3.gif.GifDecoder
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import moe.apex.breadboard.navigation.ArtistProfile
import moe.apex.breadboard.navigation.ImageView
import moe.apex.breadboard.navigation.Navigation
import moe.apex.breadboard.preferences.ImageSource
import moe.apex.breadboard.preferences.LocalPreferences
import moe.apex.breadboard.util.FlagSecureHelper
import moe.apex.breadboard.util.createViewIntent
Expand Down Expand Up @@ -81,27 +84,55 @@ class DeepLinkActivity : SingletonImageLoader.Factory, ComponentActivity(), Volu

DisposableEffect(Unit) {
val listener = Consumer<Intent> { newIntent ->
val uri = newIntent.data
if (uri != null) {
val uri = newIntent.data ?: return@Consumer

if (uri.scheme == "breadboard") {
handleBreadboardScheme(uri, prefs.imageSource)?.let {
navController.popBackStack()
navController.navigate(it)
} ?: finishAndRemoveTask()
} else {
ImageView.fromUri(uri)?.let {
navController.popBackStack()
navController.navigate(it)
} ?: ArtistProfile.fromUri(uri, prefs.imageSource)?.let {
navController.popBackStack()
navController.navigate(it)
} ?: reopenInBrowser(newIntent)
}
}
addOnNewIntentListener(listener)
onDispose { removeOnNewIntentListener(listener) }
}
intent.data?.let {
ImageView.fromUri(it)?.let { iv ->
Navigation(navController = navController, startDestination = iv)
} ?: reopenInBrowser(intent)
if (it.scheme == "breadboard") {
handleBreadboardScheme(it, prefs.imageSource)?.let { dest ->
Navigation(navController = navController, startDestination = dest)
} ?: finishAndRemoveTask()
} else {
ImageView.fromUri(it)?.let { iv ->
Navigation(navController = navController, startDestination = iv)
} ?: ArtistProfile.fromUri(it, prefs.imageSource)?.let { ap ->
Navigation(navController = navController, startDestination = ap)
} ?: reopenInBrowser(intent)
}
} ?: finishAndRemoveTask()
}
}
}


private fun handleBreadboardScheme(uri: Uri, imageSource: ImageSource): Any? {
val path = uri.pathSegments
if (uri.host == "artist") {
path.getOrNull(0)?.let {
return ArtistProfile(it, imageSource)
}
}
return null
}


private fun reopenInBrowser(intent: Intent) {
val uri = intent.data!!

Expand Down
Loading
Loading