├── .gitignore ├── .vscode └── extensions.json ├── README.md ├── bun.lockb ├── index.html ├── package.json ├── public ├── tauri.svg └── vite.svg ├── src-tauri ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── capabilities │ └── default.json ├── gen │ └── android │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── follow │ │ │ │ └── app │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values-night │ │ │ └── themes.xml │ │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ │ └── xml │ │ │ └── file_paths.xml │ │ ├── build.gradle.kts │ │ ├── buildSrc │ │ ├── build.gradle.kts │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── follow │ │ │ └── app │ │ │ └── kotlin │ │ │ ├── BuildTask.kt │ │ │ └── RustPlugin.kt │ │ ├── gradle.properties │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle ├── icons │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── 32x32.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ ├── Square30x30Logo.png │ ├── Square310x310Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── StoreLogo.png │ ├── icon.icns │ ├── icon.ico │ ├── icon.png │ └── ios │ │ ├── AppIcon-20x20@1x.png │ │ ├── AppIcon-20x20@2x-1.png │ │ ├── AppIcon-20x20@2x.png │ │ ├── AppIcon-20x20@3x.png │ │ ├── AppIcon-29x29@1x.png │ │ ├── AppIcon-29x29@2x-1.png │ │ ├── AppIcon-29x29@2x.png │ │ ├── AppIcon-29x29@3x.png │ │ ├── AppIcon-40x40@1x.png │ │ ├── AppIcon-40x40@2x-1.png │ │ ├── AppIcon-40x40@2x.png │ │ ├── AppIcon-40x40@3x.png │ │ ├── AppIcon-512@2x.png │ │ ├── AppIcon-60x60@2x.png │ │ ├── AppIcon-60x60@3x.png │ │ ├── AppIcon-76x76@1x.png │ │ ├── AppIcon-76x76@2x.png │ │ └── AppIcon-83.5x83.5@2x.png ├── src │ ├── lib.rs │ └── main.rs └── tauri.conf.json ├── src ├── App.css ├── App.tsx ├── assets │ └── react.svg ├── main.tsx ├── sw.js └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | keystore.properties 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📝 项目介绍 2 | 3 | 整体项目很简单,就是通过Webview打开Follow.is的网站,然后用Tauri生成Android编译APK所需要的文件,最后进行打包。整体APP大小在28M左右,暂时还没有做任何优化,先占个坑,在后续自己使用过程中如果发现问题会进行更新。 4 | 5 | ## 支持功能 6 | 7 | - Google和Github的登录可用 8 | - RSS正常可以阅读(Youtube订阅源暂时无法直接播放视频) 9 | - 添加订阅源正常 10 | - 大部分页面显示正常(目前还没有找到不正常的) 11 | - 使用SW进行缓存 12 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/bun.lockb -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tauri + React + Typescript 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "follow", 3 | "private": true, 4 | "version": "0.1.1", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview", 10 | "tauri": "tauri" 11 | }, 12 | "dependencies": { 13 | "@tauri-apps/api": "^2", 14 | "@tauri-apps/plugin-opener": "^2", 15 | "react": "^18.3.1", 16 | "react-dom": "^18.3.1", 17 | "vite-plugin-pwa": "^0.21.1" 18 | }, 19 | "devDependencies": { 20 | "@types/react": "^18.3.1", 21 | "@types/react-dom": "^18.3.1", 22 | "@vitejs/plugin-react": "^4.3.4", 23 | "typescript": "~5.6.2", 24 | "vite": "^6.0.3", 25 | "@tauri-apps/cli": "^2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /public/tauri.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Generated by Tauri 6 | # will have schema files for capabilities auto-completion 7 | /gen/schemas 8 | -------------------------------------------------------------------------------- /src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "follow" 3 | version = "0.1.1" 4 | description = "A Tauri App" 5 | authors = ["you"] 6 | edition = "2021" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [lib] 11 | # The `_lib` suffix may seem redundant but it is necessary 12 | # to make the lib name unique and wouldn't conflict with the bin name. 13 | # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 14 | name = "follow_lib" 15 | crate-type = ["staticlib", "cdylib", "rlib"] 16 | 17 | [build-dependencies] 18 | tauri-build = { version = "2", features = [] } 19 | 20 | [dependencies] 21 | tauri = { version = "2", features = [] } 22 | tauri-plugin-opener = "2" 23 | serde = { version = "1", features = ["derive"] } 24 | serde_json = "1" 25 | 26 | -------------------------------------------------------------------------------- /src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /src-tauri/capabilities/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../gen/schemas/desktop-schema.json", 3 | "identifier": "default", 4 | "description": "Capability for the main window", 5 | "windows": ["main"], 6 | "permissions": [ 7 | "core:default", 8 | "opener:default" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src-tauri/gen/android/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false -------------------------------------------------------------------------------- /src-tauri/gen/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | key.properties 17 | 18 | /.tauri 19 | /tauri.settings.gradle -------------------------------------------------------------------------------- /src-tauri/gen/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /src/main/java/com/follow/app/generated 2 | /src/main/jniLibs/**/*.so 3 | /src/main/assets/tauri.conf.json 4 | /tauri.build.gradle.kts 5 | /proguard-tauri.pro 6 | /tauri.properties -------------------------------------------------------------------------------- /src-tauri/gen/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.Properties 2 | import java.io.FileInputStream 3 | 4 | plugins { 5 | id("com.android.application") 6 | id("org.jetbrains.kotlin.android") 7 | id("rust") 8 | } 9 | 10 | val tauriProperties = Properties().apply { 11 | val propFile = file("tauri.properties") 12 | if (propFile.exists()) { 13 | propFile.inputStream().use { load(it) } 14 | } 15 | } 16 | 17 | android { 18 | compileSdk = 33 19 | namespace = "com.follow.app" 20 | defaultConfig { 21 | manifestPlaceholders["usesCleartextTraffic"] = "false" 22 | applicationId = "com.follow.app" 23 | minSdk = 24 24 | targetSdk = 33 25 | versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() 26 | versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") 27 | } 28 | signingConfigs { 29 | create("release") { 30 | val keystorePropertiesFile = rootProject.file("keystore.properties") 31 | val keystoreProperties = Properties() 32 | if (keystorePropertiesFile.exists()) { 33 | keystoreProperties.load(FileInputStream(keystorePropertiesFile)) 34 | } 35 | 36 | keyAlias = keystoreProperties["keyAlias"] as String 37 | keyPassword = keystoreProperties["keyPassword"] as String 38 | storeFile = file(keystoreProperties["storeFile"] as String) 39 | storePassword = keystoreProperties["storePassword"] as String 40 | } 41 | } 42 | 43 | buildTypes { 44 | getByName("debug") { 45 | manifestPlaceholders["usesCleartextTraffic"] = "true" 46 | isDebuggable = true 47 | isJniDebuggable = true 48 | isMinifyEnabled = false 49 | packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") 50 | jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") 51 | jniLibs.keepDebugSymbols.add("*/x86/*.so") 52 | jniLibs.keepDebugSymbols.add("*/x86_64/*.so") 53 | } 54 | } 55 | getByName("release") { 56 | signingConfig = signingConfigs.getByName("release") 57 | isMinifyEnabled = true 58 | proguardFiles( 59 | *fileTree(".") { include("**/*.pro") } 60 | .plus(getDefaultProguardFile("proguard-android-optimize.txt")) 61 | .toList().toTypedArray() 62 | ) 63 | } 64 | } 65 | kotlinOptions { 66 | jvmTarget = "1.8" 67 | } 68 | buildFeatures { 69 | buildConfig = true 70 | } 71 | } 72 | 73 | rust { 74 | rootDirRel = "../../../" 75 | } 76 | 77 | dependencies { 78 | implementation("androidx.webkit:webkit:1.6.1") 79 | implementation("androidx.appcompat:appcompat:1.6.1") 80 | implementation("com.google.android.material:material:1.8.0") 81 | testImplementation("junit:junit:4.13.2") 82 | androidTestImplementation("androidx.test.ext:junit:1.1.4") 83 | androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") 84 | } 85 | 86 | apply(from = "tauri.build.gradle.kts") -------------------------------------------------------------------------------- /src-tauri/gen/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/debug.keystore -------------------------------------------------------------------------------- /src-tauri/gen/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 32 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/java/com/follow/app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.follow.app 2 | 3 | class MainActivity : TauriActivity() -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | follow 3 | follow 4 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /src-tauri/gen/android/app/src/main/res/xml/file_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src-tauri/gen/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | dependencies { 7 | classpath("com.android.tools.build:gradle:8.5.1") 8 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | 19 | tasks.register("clean").configure { 20 | delete("build") 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src-tauri/gen/android/buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | gradlePlugin { 6 | plugins { 7 | create("pluginsForCoolKids") { 8 | id = "rust" 9 | implementationClass = "RustPlugin" 10 | } 11 | } 12 | } 13 | 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | compileOnly(gradleApi()) 21 | implementation("com.android.tools.build:gradle:8.5.1") 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src-tauri/gen/android/buildSrc/src/main/java/com/follow/app/kotlin/BuildTask.kt: -------------------------------------------------------------------------------- 1 | import java.io.File 2 | import org.apache.tools.ant.taskdefs.condition.Os 3 | import org.gradle.api.DefaultTask 4 | import org.gradle.api.GradleException 5 | import org.gradle.api.logging.LogLevel 6 | import org.gradle.api.tasks.Input 7 | import org.gradle.api.tasks.TaskAction 8 | 9 | open class BuildTask : DefaultTask() { 10 | @Input 11 | var rootDirRel: String? = null 12 | @Input 13 | var target: String? = null 14 | @Input 15 | var release: Boolean? = null 16 | 17 | @TaskAction 18 | fun assemble() { 19 | val executable = """bun"""; 20 | try { 21 | runTauriCli(executable) 22 | } catch (e: Exception) { 23 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 24 | runTauriCli("$executable.cmd") 25 | } else { 26 | throw e; 27 | } 28 | } 29 | } 30 | 31 | fun runTauriCli(executable: String) { 32 | val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") 33 | val target = target ?: throw GradleException("target cannot be null") 34 | val release = release ?: throw GradleException("release cannot be null") 35 | val args = listOf("tauri", "android", "android-studio-script"); 36 | 37 | project.exec { 38 | workingDir(File(project.projectDir, rootDirRel)) 39 | executable(executable) 40 | args(args) 41 | if (project.logger.isEnabled(LogLevel.DEBUG)) { 42 | args("-vv") 43 | } else if (project.logger.isEnabled(LogLevel.INFO)) { 44 | args("-v") 45 | } 46 | if (release) { 47 | args("--release") 48 | } 49 | args(listOf("--target", target)) 50 | }.assertNormalExitValue() 51 | } 52 | } -------------------------------------------------------------------------------- /src-tauri/gen/android/buildSrc/src/main/java/com/follow/app/kotlin/RustPlugin.kt: -------------------------------------------------------------------------------- 1 | import com.android.build.api.dsl.ApplicationExtension 2 | import org.gradle.api.DefaultTask 3 | import org.gradle.api.Plugin 4 | import org.gradle.api.Project 5 | import org.gradle.kotlin.dsl.configure 6 | import org.gradle.kotlin.dsl.get 7 | 8 | const val TASK_GROUP = "rust" 9 | 10 | open class Config { 11 | lateinit var rootDirRel: String 12 | } 13 | 14 | open class RustPlugin : Plugin { 15 | private lateinit var config: Config 16 | 17 | override fun apply(project: Project) = with(project) { 18 | config = extensions.create("rust", Config::class.java) 19 | 20 | val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"); 21 | val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList 22 | 23 | val defaultArchList = listOf("arm64", "arm", "x86", "x86_64"); 24 | val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList 25 | 26 | val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64") 27 | 28 | extensions.configure { 29 | @Suppress("UnstableApiUsage") 30 | flavorDimensions.add("abi") 31 | productFlavors { 32 | create("universal") { 33 | dimension = "abi" 34 | ndk { 35 | abiFilters += abiList 36 | } 37 | } 38 | defaultArchList.forEachIndexed { index, arch -> 39 | create(arch) { 40 | dimension = "abi" 41 | ndk { 42 | abiFilters.add(defaultAbiList[index]) 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | afterEvaluate { 50 | for (profile in listOf("debug", "release")) { 51 | val profileCapitalized = profile.replaceFirstChar { it.uppercase() } 52 | val buildTask = tasks.maybeCreate( 53 | "rustBuildUniversal$profileCapitalized", 54 | DefaultTask::class.java 55 | ).apply { 56 | group = TASK_GROUP 57 | description = "Build dynamic library in $profile mode for all targets" 58 | } 59 | 60 | tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask) 61 | 62 | for (targetPair in targetsList.withIndex()) { 63 | val targetName = targetPair.value 64 | val targetArch = archList[targetPair.index] 65 | val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() } 66 | val targetBuildTask = project.tasks.maybeCreate( 67 | "rustBuild$targetArchCapitalized$profileCapitalized", 68 | BuildTask::class.java 69 | ).apply { 70 | group = TASK_GROUP 71 | description = "Build dynamic library in $profile mode for $targetArch" 72 | rootDirRel = config.rootDirRel 73 | target = targetName 74 | release = profile == "release" 75 | } 76 | 77 | buildTask.dependsOn(targetBuildTask) 78 | tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn( 79 | targetBuildTask 80 | ) 81 | } 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src-tauri/gen/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | android.nonFinalResIds=false -------------------------------------------------------------------------------- /src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue May 10 19:22:52 CST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /src-tauri/gen/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src-tauri/gen/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src-tauri/gen/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | apply from: 'tauri.settings.gradle' 4 | -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-20x20@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-20x20@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-20x20@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-20x20@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-29x29@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-29x29@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-29x29@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-29x29@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-40x40@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-40x40@2x-1.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-40x40@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-40x40@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-512@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-60x60@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-60x60@3x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-76x76@1x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-76x76@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moreoronce/followforandroid/2be607b61ae24aa5d475a01463fd7a546c57f9c5/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /src-tauri/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ 2 | #[tauri::command] 3 | fn greet(name: &str) -> String { 4 | format!("Hello, {}! You've been greeted from Rust!", name) 5 | } 6 | 7 | #[cfg_attr(mobile, tauri::mobile_entry_point)] 8 | pub fn run() { 9 | tauri::Builder::default() 10 | .plugin(tauri_plugin_opener::init()) 11 | .invoke_handler(tauri::generate_handler![greet]) 12 | .run(tauri::generate_context!()) 13 | .expect("error while running tauri application"); 14 | } 15 | -------------------------------------------------------------------------------- /src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | follow_lib::run() 6 | } 7 | -------------------------------------------------------------------------------- /src-tauri/tauri.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.tauri.app/config/2", 3 | "productName": "follow", 4 | "version": "0.1.2", 5 | "identifier": "com.follow.app", 6 | "build": { 7 | "beforeDevCommand": "bun run dev", 8 | "devUrl": "http://localhost:1420", 9 | "beforeBuildCommand": "bun run build", 10 | "frontendDist": "../dist" 11 | }, 12 | "app": { 13 | "windows": [ 14 | { 15 | "title": "follow", 16 | "decorations": false, 17 | "width": 1280, 18 | "height": 800, 19 | "resizable": true, 20 | "fullscreen": false, 21 | "url": "https://app.follow.is", 22 | "userAgent": "Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36" 23 | } 24 | ], 25 | "security": { 26 | "csp": "default-src 'self' https://app.follow.is; connect-src 'self' https://app.follow.is; img-src 'self' https://app.follow.is data:; script-src 'self' https://app.follow.is; style-src 'self' https://app.follow.is 'unsafe-inline';" 27 | } 28 | }, 29 | "bundle": { 30 | "active": true, 31 | "targets": "all", 32 | "icon": [ 33 | "icons/128x128.png", 34 | "icons/icon.png" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .logo.vite:hover { 2 | filter: drop-shadow(0 0 2em #747bff); 3 | } 4 | 5 | .logo.react:hover { 6 | filter: drop-shadow(0 0 2em #61dafb); 7 | } 8 | :root { 9 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 10 | font-size: 16px; 11 | line-height: 24px; 12 | font-weight: 400; 13 | 14 | color: #0f0f0f; 15 | background-color: #f6f6f6; 16 | 17 | font-synthesis: none; 18 | text-rendering: optimizeLegibility; 19 | -webkit-font-smoothing: antialiased; 20 | -moz-osx-font-smoothing: grayscale; 21 | -webkit-text-size-adjust: 100%; 22 | } 23 | 24 | .container { 25 | margin: 0; 26 | padding-top: 10vh; 27 | display: flex; 28 | flex-direction: column; 29 | justify-content: center; 30 | text-align: center; 31 | } 32 | 33 | .logo { 34 | height: 6em; 35 | padding: 1.5em; 36 | will-change: filter; 37 | transition: 0.75s; 38 | } 39 | 40 | .logo.tauri:hover { 41 | filter: drop-shadow(0 0 2em #24c8db); 42 | } 43 | 44 | .row { 45 | display: flex; 46 | justify-content: center; 47 | } 48 | 49 | a { 50 | font-weight: 500; 51 | color: #646cff; 52 | text-decoration: inherit; 53 | } 54 | 55 | a:hover { 56 | color: #535bf2; 57 | } 58 | 59 | h1 { 60 | text-align: center; 61 | } 62 | 63 | input, 64 | button { 65 | border-radius: 8px; 66 | border: 1px solid transparent; 67 | padding: 0.6em 1.2em; 68 | font-size: 1em; 69 | font-weight: 500; 70 | font-family: inherit; 71 | color: #0f0f0f; 72 | background-color: #ffffff; 73 | transition: border-color 0.25s; 74 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); 75 | } 76 | 77 | button { 78 | cursor: pointer; 79 | } 80 | 81 | button:hover { 82 | border-color: #396cd8; 83 | } 84 | button:active { 85 | border-color: #396cd8; 86 | background-color: #e8e8e8; 87 | } 88 | 89 | input, 90 | button { 91 | outline: none; 92 | } 93 | 94 | #greet-input { 95 | margin-right: 5px; 96 | } 97 | 98 | @media (prefers-color-scheme: dark) { 99 | :root { 100 | color: #f6f6f6; 101 | background-color: #2f2f2f; 102 | } 103 | 104 | a:hover { 105 | color: #24c8db; 106 | } 107 | 108 | input, 109 | button { 110 | color: #ffffff; 111 | background-color: #0f0f0f98; 112 | } 113 | button:active { 114 | background-color: #0f0f0f69; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import reactLogo from "./assets/react.svg"; 3 | import { invoke } from "@tauri-apps/api/core"; 4 | import "./App.css"; 5 | 6 | function registerServiceWorker() { 7 | if ("serviceWorker" in navigator) { 8 | window.addEventListener("load", () => { 9 | navigator.serviceWorker 10 | .register("/sw.js") 11 | .then(() => { 12 | console.log("ServiceWorker registration successful"); 13 | }) 14 | .catch((err) => { 15 | console.log("ServiceWorker registration failed: ", err); 16 | }); 17 | }); 18 | } 19 | } 20 | 21 | function App() { 22 | useEffect(() => { 23 | registerServiceWorker(); 24 | }, []); 25 | 26 | const [greetMsg, setGreetMsg] = useState(""); 27 | const [name, setName] = useState(""); 28 | 29 | async function greet() { 30 | // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ 31 | setGreetMsg(await invoke("greet", { name })); 32 | } 33 | 34 | return ( 35 |
36 |

Welcome to Tauri + React

37 | 38 |
39 | 40 | Vite logo 41 | 42 | 43 | Tauri logo 44 | 45 | 46 | React logo 47 | 48 |
49 |

Click on the Tauri, Vite, and React logos to learn more.

50 | 51 |
{ 54 | e.preventDefault(); 55 | greet(); 56 | }} 57 | > 58 | setName(e.currentTarget.value)} 61 | placeholder="Enter a name..." 62 | /> 63 | 64 |
65 |

{greetMsg}

66 |
67 | ); 68 | } 69 | 70 | export default App; 71 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( 6 | 7 | 8 | , 9 | ); 10 | -------------------------------------------------------------------------------- /src/sw.js: -------------------------------------------------------------------------------- 1 | const CACHE_NAME = "follow-cache-v1"; 2 | const ASSETS = [ 3 | "/", 4 | "/index.html", 5 | "/assets/**/*", 6 | "https://app.follow.is/**/*" 7 | ]; 8 | 9 | // 添加调试日志 10 | console.log('[Service Worker] Installing...'); 11 | 12 | self.addEventListener("install", (event) => { 13 | event.waitUntil( 14 | caches.open(CACHE_NAME).then((cache) => { 15 | return cache.addAll(ASSETS); 16 | }) 17 | ); 18 | }); 19 | 20 | self.addEventListener("fetch", (event) => { 21 | console.log(`[Service Worker] Fetching: ${event.request.url}`); 22 | 23 | event.respondWith( 24 | caches.match(event.request).then((response) => { 25 | if (response) { 26 | console.log(`[Service Worker] Serving from cache: ${event.request.url}`); 27 | return response; 28 | } 29 | 30 | console.log(`[Service Worker] Fetching from network: ${event.request.url}`); 31 | return fetch(event.request) 32 | .then((networkResponse) => { 33 | // 缓存新的响应 34 | return caches.open(CACHE_NAME).then((cache) => { 35 | cache.put(event.request, networkResponse.clone()); 36 | return networkResponse; 37 | }); 38 | }) 39 | .catch((error) => { 40 | console.error(`[Service Worker] Network request failed: ${error.message}`); 41 | // 回退到缓存中的旧响应 42 | return caches.match(event.request).then((cachedResponse) => { 43 | if (cachedResponse) { 44 | console.log(`[Service Worker] Serving fallback from cache: ${event.request.url}`); 45 | return cachedResponse; 46 | } 47 | throw error; // 如果没有缓存,抛出错误 48 | }); 49 | }); 50 | }) 51 | ); 52 | }); 53 | 54 | self.addEventListener("activate", (event) => { 55 | event.waitUntil( 56 | caches.keys().then((cacheNames) => { 57 | return Promise.all( 58 | cacheNames 59 | .filter((name) => name !== CACHE_NAME) 60 | .map((name) => caches.delete(name)) 61 | ); 62 | }) 63 | ); 64 | }); -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { VitePWA } from "vite-plugin-pwa"; 4 | 5 | // @ts-expect-error process is a nodejs global 6 | const host = process.env.TAURI_DEV_HOST; 7 | 8 | // https://vitejs.dev/config/ 9 | export default defineConfig(async () => ({ 10 | plugins: [ 11 | react(), 12 | VitePWA({ 13 | registerType: "autoUpdate", 14 | manifest: false, 15 | workbox: { 16 | globPatterns: ["**/*.{js,css,html,ico,png,svg}"], 17 | runtimeCaching: [ 18 | { 19 | urlPattern: /^https:\/\/app\.follow\.is\/.*/i, 20 | handler: "NetworkFirst", 21 | options: { 22 | cacheName: "follow-cache", 23 | expiration: { 24 | maxEntries: 100, 25 | maxAgeSeconds: 60 * 60 * 24 * 30, // 30 days 26 | }, 27 | cacheableResponse: { 28 | statuses: [0, 200], 29 | }, 30 | networkTimeoutSeconds: 3, // 回退到缓存前的网络超时时间 31 | }, 32 | }, 33 | ], 34 | }, 35 | }), 36 | ], 37 | 38 | build: { 39 | rollupOptions: { 40 | output: { 41 | manualChunks: { 42 | vendor: ["react", "react-dom"], 43 | }, 44 | }, 45 | }, 46 | }, 47 | 48 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 49 | // 50 | // 1. prevent vite from obscuring rust errors 51 | clearScreen: false, 52 | // 2. tauri expects a fixed port, fail if that port is not available 53 | server: { 54 | port: 1420, 55 | strictPort: true, 56 | host: host || false, 57 | hmr: host 58 | ? { 59 | protocol: "ws", 60 | host, 61 | port: 1421, 62 | } 63 | : undefined, 64 | watch: { 65 | // 3. tell vite to ignore watching `src-tauri` 66 | ignored: ["**/src-tauri/**"], 67 | }, 68 | }, 69 | })); 70 | --------------------------------------------------------------------------------