├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── en-bug-report.yml
│ ├── en-feature-request.yml
│ ├── ja-bug-report.yml
│ ├── ja-feature-request.yml
│ ├── redirected-from-app.yml
│ └── translation-error.yml
└── dependabot.yml
├── .gitignore
├── .metadata
├── .vscode
├── launch.json
└── settings.json
├── LICENSE
├── README-ja.md
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── vrc_manager
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-hdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-mdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-xhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-xxhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── build
│ └── .last_build_id
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── img
│ ├── FutureGraphics.kra
│ ├── FutureGraphics.png
│ ├── foreground.kra
│ ├── foreground.png
│ ├── icon.kra
│ └── icon.png
├── svg
│ ├── bandsintown.svg
│ ├── behance.svg
│ ├── codepen.svg
│ ├── dribbble.svg
│ ├── dropbox.svg
│ ├── email.svg
│ ├── facebook.svg
│ ├── fivehundredpix.svg
│ ├── flickr.svg
│ ├── foursquare.svg
│ ├── github.svg
│ ├── google.svg
│ ├── google_play.svg
│ ├── instagram.svg
│ ├── itunes.svg
│ ├── linkedin.svg
│ ├── mailto.svg
│ ├── medium.svg
│ ├── meetup.svg
│ ├── pinterest.svg
│ ├── rdio.svg
│ ├── reddit.svg
│ ├── rss.svg
│ ├── sharethis.svg
│ ├── smugmug.svg
│ ├── snapchat.svg
│ ├── soundcloud.svg
│ ├── spotify.svg
│ ├── squarespace.svg
│ ├── tumblr.svg
│ ├── twitch.svg
│ ├── twitter.svg
│ ├── vevo.svg
│ ├── vimeo.svg
│ ├── vine.svg
│ ├── vk.svg
│ ├── vsco.svg
│ ├── wechat.svg
│ ├── whatsapp.svg
│ ├── yelp.svg
│ └── youtube.svg
└── tools
│ ├── error_handling_checker.py
│ ├── l10n
│ ├── checker.py
│ ├── marge.py
│ ├── to_arb.py
│ └── to_txt.py
│ └── svg
│ ├── svg.json
│ └── svg.py
├── build.ps1
├── cspell.json
├── docs
├── contribute
│ ├── en.md
│ └── ja.md
├── img
│ ├── screenshots1.png
│ ├── screenshots2.png
│ ├── screenshots3.png
│ ├── screenshots4.png
│ └── screenshots5.png
├── privacy_policy
│ ├── en.md
│ └── ja.md
└── user_policies
│ ├── en.md
│ └── ja.md
├── gen.ps1
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── l10n.yaml
├── lib
├── api
│ ├── .gitignore
│ ├── assets
│ │ ├── assets.dart
│ │ ├── icon.dart
│ │ ├── instance_type.dart
│ │ ├── lang.dart
│ │ ├── region.dart
│ │ └── status.dart
│ ├── data_class.dart
│ ├── data_class_ext.dart
│ └── main.dart
├── assets.dart
├── assets
│ ├── anchor.dart
│ ├── api
│ │ ├── get.dart
│ │ └── post.dart
│ ├── conditions.dart
│ ├── date.dart
│ ├── flutter
│ │ ├── text_stream.dart
│ │ └── url_parser.dart
│ ├── license.dart
│ ├── session.dart
│ ├── sort
│ │ ├── users.dart
│ │ └── worlds.dart
│ ├── storage.dart
│ └── theme
│ │ ├── enum.dart
│ │ └── true_black.dart
├── l10n
│ ├── app_en.arb
│ ├── app_es.arb
│ ├── app_ja.arb
│ ├── app_pt.arb
│ ├── app_ru.arb
│ ├── app_th.arb
│ ├── app_zh.arb
│ └── code.dart
├── main.dart
├── scenes
│ ├── core
│ │ └── splash.dart
│ ├── main
│ │ ├── friend_request.dart
│ │ ├── friends.dart
│ │ ├── main.dart
│ │ ├── search.dart
│ │ └── worlds_favorite.dart
│ ├── setting
│ │ ├── accessibility.dart
│ │ ├── account.dart
│ │ ├── help.dart
│ │ ├── logger.dart
│ │ ├── other_account.dart
│ │ ├── permissions.dart
│ │ ├── settings.dart
│ │ └── token.dart
│ ├── sub
│ │ ├── json_viewer.dart
│ │ ├── login.dart
│ │ ├── self.dart
│ │ ├── user.dart
│ │ └── world.dart
│ └── web
│ │ ├── web_view.dart
│ │ ├── web_view_login.dart
│ │ └── web_view_policies.dart
├── storage
│ ├── accessibility.dart
│ ├── account.dart
│ ├── grid_modal.dart
│ └── user_policy.dart
└── widgets
│ ├── config_modal
│ ├── locale.dart
│ └── theme.dart
│ ├── drawer.dart
│ ├── future
│ ├── button.dart
│ └── tile.dart
│ ├── grid_modal
│ ├── config.dart
│ └── modal.dart
│ ├── grid_view
│ ├── extraction
│ │ ├── consumer.dart
│ │ └── render_grid
│ │ │ ├── favorite_world.dart
│ │ │ ├── friends.dart
│ │ │ ├── user.dart
│ │ │ └── world.dart
│ ├── template
│ │ └── template.dart
│ └── widget
│ │ └── world.dart
│ ├── loading.dart
│ ├── lunch_world.dart
│ ├── modal.dart
│ ├── modal
│ ├── share.dart
│ ├── user.dart
│ └── world.dart
│ ├── region.dart
│ ├── scroll.dart
│ ├── share.dart
│ ├── status.dart
│ ├── user.dart
│ └── world.dart
├── pubspec.lock
├── pubspec.yaml
└── windows
├── .gitignore
├── CMakeLists.txt
├── build.ps1
├── flutter
├── CMakeLists.txt
├── generated_plugin_registrant.cc
├── generated_plugin_registrant.h
└── generated_plugins.cmake
├── runner
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── resources
│ └── app_icon.ico
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
└── setup.iss
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/en-bug-report.yml:
--------------------------------------------------------------------------------
1 | name: "[en] 🐛 Report a bug"
2 | description: Report a bug in vrc_manager.
3 | labels: ["bug"]
4 | body:
5 |
6 | - type: input
7 | id: os
8 | attributes:
9 | label: OS
10 | description: Please include the version.
11 | placeholder: "Example: Android 12, Window 10"
12 | validations:
13 | required: true
14 |
15 | - type: input
16 | id: device-name
17 | attributes:
18 | label: Device name
19 | placeholder: "Example: Samsung Galaxy S22 Ultra"
20 | validations:
21 | required: true
22 |
23 | - type: input
24 | id: country-of-origin
25 | attributes:
26 | label: Country of origin of connection
27 | placeholder: "Example: Japan"
28 | validations:
29 | required: true
30 |
31 | - type: dropdown
32 | id: download-location
33 | attributes:
34 | label: Where you downloaded the app
35 | options:
36 | - Github(GMS)
37 | - Github(HMS)
38 | - Github(Windows)
39 | - Google Play Store
40 | - HUAWEI AppGallery
41 | - Xiaomi GetApps
42 | - Other
43 | validations:
44 | required: true
45 |
46 | - type: dropdown
47 | id: reinstall
48 | attributes:
49 | label: Have you reinstalled it ?
50 | options:
51 | - "Yes"
52 | - No, perhaps that won't be necessary.
53 | validations:
54 | required: true
55 |
56 | - type: textarea
57 | id: bug-description
58 | attributes:
59 | label: Bug description
60 | description: Describe in detail what the bug is about. Include the expected behaviour and actual behaviour. Please attach images if necessary.
61 | validations:
62 | required: true
63 |
64 | - type: textarea
65 | id: steps-to-reproduce
66 | attributes:
67 | label: Steps to reproduce
68 | description: Provide detailed intructions to trigger the bug.
69 | placeholder: |
70 | Example:
71 | 1. Open "Online Friends"
72 | 2. Change the display setting from "Default" to "Simple"
73 | 3. ...
74 | ...
75 | validations:
76 | required: true
77 |
78 | - type: textarea
79 | id: error-message
80 | attributes:
81 | label: Relevant error message output
82 | description: Please paste any relevant Relevant error message output.
83 | render: shell
84 | validations:
85 | required: false
86 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/en-feature-request.yml:
--------------------------------------------------------------------------------
1 | name: "[en] 💡 Request a feature"
2 | description: Please suggest features you would like to see in vrc_manager
3 | labels: ["enhancement"]
4 | body:
5 |
6 | - type: textarea
7 | id: feature-description
8 | attributes:
9 | label: Describe the feature
10 | validations:
11 | required: true
12 |
13 | - type: textarea
14 | id: feature-reasoning
15 | attributes:
16 | label: How is this feature useful to users?
17 | validations:
18 | required: true
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/ja-bug-report.yml:
--------------------------------------------------------------------------------
1 | name: "[ja] 🐛 バグを報告する"
2 | description: vrc_managerの不具合を報告する。
3 | labels: ["bug"]
4 | body:
5 |
6 | - type: input
7 | id: os
8 | attributes:
9 | label: OS
10 | description: バージョンも含めてください
11 | placeholder: "例: Android 12, Window 10"
12 | validations:
13 | required: true
14 |
15 | - type: input
16 | id: device-name
17 | attributes:
18 | label: 端末名
19 | placeholder: "例: Samsung Galaxy S22 Ultra"
20 | validations:
21 | required: true
22 |
23 | - type: input
24 | id: country-of-origin
25 | attributes:
26 | label: 接続元の国名
27 | placeholder: "例: 日本"
28 | validations:
29 | required: true
30 |
31 | - type: dropdown
32 | id: download-location
33 | attributes:
34 | label: アプリをダウンロードした場所
35 | options:
36 | - Github(GMS)
37 | - Github(HMS)
38 | - Github(Windows)
39 | - Google Play Store
40 | - HUAWEI AppGallery
41 | - Xiaomi GetApps
42 | - Other
43 | validations:
44 | required: true
45 |
46 | - type: dropdown
47 | id: reinstall
48 | attributes:
49 | label: 再インストールしましたか?
50 | options:
51 | - はい
52 | - いいえ、恐らくその必要はない
53 | validations:
54 | required: true
55 |
56 | - type: textarea
57 | id: bug-description
58 | attributes:
59 | label: 不具合の説明
60 | description: バグの内容を詳しく記述してください。期待される動作と実際の動作を含めてください。必要があれば画像を添付して下さい。
61 | validations:
62 | required: true
63 |
64 | - type: textarea
65 | id: steps-to-reproduce
66 | attributes:
67 | label: 不具合を起こすための手順
68 | description: バグを発生させるための詳細な手順を記述してください。
69 | placeholder: |
70 | 例:
71 | 1. 「オンラインのフレンド」を開きます
72 | 2. 表示設定を「デフォルト」から「シンプル」に変更します
73 | 3. ...
74 | ...
75 | validations:
76 | required: true
77 |
78 | - type: textarea
79 | id: error-message
80 | attributes:
81 | label: エラーメッセージ
82 | description: エラーメッセージが表示されていればそれを貼り付けてください。
83 | render: shell
84 | validations:
85 | required: false
86 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/ja-feature-request.yml:
--------------------------------------------------------------------------------
1 | name: "[ja] 💡 機能を提案する"
2 | description: vrc_managerに欲しい機能を提案して下さい
3 | labels: ["enhancement"]
4 | body:
5 |
6 | - type: textarea
7 | id: feature-description
8 | attributes:
9 | label: 機能を説明する
10 | validations:
11 | required: true
12 |
13 | - type: textarea
14 | id: feature-reasoning
15 | attributes:
16 | label: この機能はユーザーにとってどのように役に立つのでしょうか?
17 | validations:
18 | required: true
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/redirected-from-app.yml:
--------------------------------------------------------------------------------
1 | name: "📓 Redirected from app"
2 | description: Report error message in vrc_manager.
3 | labels: ["bug"]
4 | body:
5 |
6 | - type: textarea
7 | id: steps-to-reproduce
8 | attributes:
9 | label: Steps to reproduce
10 | description: Provide detailed intructions to trigger the bug.
11 | placeholder: |
12 | Example:
13 | 1. Start with all application data deleted.
14 | 2. Login and open Home
15 | 3. ...
16 | ...
17 | validations:
18 | required: true
19 |
20 | - type: dropdown
21 | id: download-location
22 | attributes:
23 | label: Where you downloaded the app
24 | options:
25 | - Github(GMS)
26 | - Github(HMS)
27 | - Github(Windows)
28 | - Google Play Store
29 | - HUAWEI AppGallery
30 | - Xiaomi GetApps
31 | - Other
32 | validations:
33 | required: true
34 |
35 | - type: textarea
36 | id: error-message
37 | attributes:
38 | label: Relevant error message output
39 | description: Please paste the log. Logs are automatically copied to the clipboard.
40 | render: shell
41 | validations:
42 | required: true
43 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/translation-error.yml:
--------------------------------------------------------------------------------
1 | name: "📓 Report a translation error"
2 | description: Report error message in vrc_manager.
3 | labels: ["bug"]
4 | body:
5 |
6 | - type: dropdown
7 | id: language
8 | attributes:
9 | label: Language
10 | options:
11 | - English
12 | - 日本語
13 | - español
14 | - Português
15 | - русский
16 | - ไทย
17 | - 简体中文
18 | - Other
19 | validations:
20 | required: true
21 |
22 | - type: dropdown
23 | id: locale-native-speaker
24 | attributes:
25 | label: Are you a native speaker of the language?
26 | options:
27 | - "True"
28 | - "False"
29 | validations:
30 | required: true
31 |
32 | - type: textarea
33 | id: steps-to-reproduce
34 | attributes:
35 | label: Steps to reproduce
36 | description: Procedure for displaying translation errors.
37 | placeholder: |
38 | Example:
39 | 1. Open "Setting"
40 | 2. Open "Accessibility"
41 | validations:
42 | required: true
43 |
44 |
45 | - type: input
46 | id: incorrect-translation
47 | attributes:
48 | label: Incorrect translation
49 | description: Please enter the incorrect translation.
50 | placeholder: "Example: 3 Billion Devices Run Coffee."
51 | validations:
52 | required: true
53 |
54 | - type: input
55 | id: correct-translation
56 | attributes:
57 | label: Correct translation
58 | description: Please enter the correct translation.
59 | placeholder: "Example: 3 Billion Devices Run Java."
60 | validations:
61 | required: true
62 |
63 |
64 | - type: textarea
65 | id: note
66 | attributes:
67 | label: Note
68 | description: Please indicate anything else of note.
69 | validations:
70 | required: false
71 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "pub" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: "4cf269e36de2573851eaef3c763994f8f9be494d"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
17 | base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
18 | - platform: windows
19 | create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
20 | base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
21 |
22 | # User provided section
23 |
24 | # List of Local paths (relative to this file) that should be
25 | # ignored by the migrate tool.
26 | #
27 | # Files that are not part of the templates will be ignored by default.
28 | unmanaged_files:
29 | - 'lib/main.dart'
30 | - 'ios/Runner.xcodeproj/project.pbxproj'
31 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // IntelliSense を使用して利用可能な属性を学べます。
3 | // 既存の属性の説明をホバーして表示します。
4 | // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "vrchat_mobile_client",
9 | "request": "launch",
10 | "type": "dart"
11 | },
12 | {
13 | "name": "vrchat_mobile_client (profile mode)",
14 | "request": "launch",
15 | "type": "dart",
16 | "flutterMode": "profile"
17 | },
18 | {
19 | "name": "vrchat_mobile_client (release mode)",
20 | "request": "launch",
21 | "type": "dart",
22 | "flutterMode": "release"
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "dart.lineLength": 160,
3 | "markdownlint.config": {
4 | "MD033": false
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 yuki
4 |
5 | https://yuki0311.com/
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/README-ja.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | マルチプラットフォーム Android, Windows(残念ながら Macbook を持っていません😫)
8 | 多言語対応 en, ja, es, pt, ru, th, zh
9 | 複数のログイン方法に対応 2fa, WebView, Token
10 | 複数のアカウントに対応 Just H 用のアカウントをお持ちですか?
11 | 全て無料 もちろん広告もなし
12 | アプリリンクに対応 URL から直接アプリを開けます
13 | 洗練された UI モダンなデザイン
14 | ダークテーマに対応 6種類のテーマと3種類の表示方法
15 |
16 |
17 |
18 | [English](README.md) / [Japanese](README-ja.md)
19 |
20 |
21 |
22 | ## インストール
23 |
24 | ### Android
25 |
26 | - [**play.google.com**](https://play.google.com/store/apps/details?id=com.yuki0311.vrc_manager)
27 | - [**appgallery.huawei.com**](https://appgallery.huawei.com/#/app/C106854219) **(非推奨)**
28 | - [**Releases**](https://github.com/fa0311/vrc_manager/releases)の**app-release.apk**
29 |
30 | ### Windows
31 |
32 | - [**Releases**](https://github.com/fa0311/vrc_manager/releases)の**VRCManager-Setup.exe**
33 |
34 | ## ドキュメント
35 |
36 | 開発・翻訳を手伝ってみませんか? [**貢献**](docs/contribute/ja.md)
37 |
38 | ## 免責事項
39 |
40 | VRChat API の使用に関する VRChat チーム(Tupper 氏)の公式な回答です。
41 |
42 | > Use of the API using applications other than the approved methods (website, VRChat application) are not officially supported. You may use the API for your own application, but keep these guidelines in mind:
43 | >
44 | > - We do not provide documentation or support for the API.
45 | > - Do not make queries to the API more than once per 60 seconds.
46 | > - Abuse of the API may result in account termination.
47 | > - Access to API endpoints may break at any given time, with no warning.
48 | >
49 | > [出典](https://vrchatapi.github.io/sdk/java/)
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Multi platform Android, Windows (unfortunately I don't have a Macbook😫)
8 | Multilingual support en, ja, es, pt, ru, th, zh
9 | Support for multiple login methods 2fa, WebView, Token
10 | Multiple account support Do you have a Just H account?
11 | Free for all And of course, no ads.
12 | Supports application links You can open the app directly from the URL
13 | Sophisticated UI Modern design
14 | Supports dark themes 6 different themes and 3 different display methods
15 |
16 |
17 |
18 | [English](README.md) / [Japanese](README-ja.md)
19 |
20 |
21 |
22 | ## Install
23 |
24 | ### Android
25 |
26 | - [**play.google.com**](https://play.google.com/store/apps/details?id=com.yuki0311.vrc_manager)
27 | - [**appgallery.huawei.com**](https://appgallery.huawei.com/#/app/C106854219) **(deprecated)**
28 | - [**Releases**](https://github.com/fa0311/vrc_manager/releases) **app-release.apk**
29 |
30 | ### Windows
31 |
32 | - [**Releases**](https://github.com/fa0311/vrc_manager/releases) **VRCManager-Setup.exe**
33 |
34 | ## Documents
35 |
36 | Want to help with development and translation? [**contribute**](docs/contribute/en.md)
37 |
38 | ## Disclaimer
39 |
40 | This is the official response of the VRChat Team (from Tupper more specifically) on the usage of the VRChat API.
41 |
42 | > Use of the API using applications other than the approved methods (website, VRChat application) are not officially supported. You may use the API for your own application, but keep these guidelines in mind:
43 | >
44 | > - We do not provide documentation or support for the API.
45 | > - Do not make queries to the API more than once per 60 seconds.
46 | > - Abuse of the API may result in account termination.
47 | > - Access to API endpoints may break at any given time, with no warning.
48 | >
49 | > [Reference](https://vrchatapi.github.io/sdk/java/)
50 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | analyzer:
2 | errors:
3 | deprecated_member_use: ignore
4 | include: package:flutter_lints/flutter.yaml
5 |
6 | linter:
7 | rules:
8 | use_build_context_synchronously: false
9 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/to/reference-keystore
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.android.application"
3 | id "kotlin-android"
4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
5 | id "dev.flutter.flutter-gradle-plugin"
6 | }
7 |
8 | def keystoreProperties = new Properties()
9 | def keystorePropertiesFile = rootProject.file('key.properties')
10 | if (keystorePropertiesFile.exists()) {
11 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
12 | }
13 |
14 | android {
15 | namespace = "com.yuki0311.vrc_manager"
16 | compileSdk = flutter.compileSdkVersion
17 | ndkVersion = flutter.ndkVersion
18 |
19 | compileOptions {
20 | sourceCompatibility = JavaVersion.VERSION_1_8
21 | targetCompatibility = JavaVersion.VERSION_1_8
22 | }
23 |
24 | kotlinOptions {
25 | jvmTarget = JavaVersion.VERSION_1_8
26 | }
27 |
28 | defaultConfig {
29 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
30 | applicationId = "com.yuki0311.vrc_manager"
31 | // You can update the following values to match your application needs.
32 | // For more information, see: https://flutter.dev/to/review-gradle-config.
33 | minSdk = flutter.minSdkVersion
34 | targetSdk = flutter.targetSdkVersion
35 | versionCode = flutter.versionCode
36 | versionName = flutter.versionName
37 | }
38 |
39 | signingConfigs {
40 | release {
41 | keyAlias keystoreProperties['keyAlias']
42 | keyPassword keystoreProperties['keyPassword']
43 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
44 | storePassword keystoreProperties['storePassword']
45 | }
46 | }
47 |
48 |
49 | buildTypes {
50 | release {
51 | // TODO: Add your own signing config for the release build.
52 | // Signing with the debug keys for now, so `flutter run --release` works.
53 | signingConfig signingConfigs.release
54 | }
55 | }
56 | }
57 |
58 |
59 | java {
60 | toolchain {
61 | languageVersion = JavaLanguageVersion.of(17)
62 | }
63 | }
64 |
65 | flutter {
66 | source = "../.."
67 | }
68 |
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # https://github.com/mogol/flutter_secure_storage/issues/748
2 | -dontwarn com.google.errorprone.annotations.CanIgnoreReturnValue
3 | -dontwarn com.google.errorprone.annotations.CheckReturnValue
4 | -dontwarn com.google.errorprone.annotations.Immutable
5 | -dontwarn com.google.errorprone.annotations.RestrictedApi
6 | -dontwarn javax.annotation.Nullable
7 | -dontwarn javax.annotation.concurrent.GuardedBy
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
22 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
43 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/vrc_manager/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.yuki0311.vrc_manager
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity()
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffffff
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | subprojects {
7 | afterEvaluate { project ->
8 | if (project.hasProperty('android')) {
9 | project.android {
10 | if (namespace == null) {
11 | namespace project.group
12 | }
13 | }
14 | }
15 | }
16 | }
17 | }
18 |
19 | rootProject.buildDir = "../build"
20 | subprojects {
21 | project.buildDir = "${rootProject.buildDir}/${project.name}"
22 | }
23 | subprojects {
24 | project.evaluationDependsOn(":app")
25 | }
26 |
27 | tasks.register("clean", Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/android/build/.last_build_id:
--------------------------------------------------------------------------------
1 | 32031a0bdc0e7e5eafe51aacb3b02d03
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }()
9 |
10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
11 |
12 | repositories {
13 | google()
14 | mavenCentral()
15 | gradlePluginPortal()
16 | }
17 | }
18 |
19 | plugins {
20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
21 | id "com.android.application" version "8.1.0" apply false
22 | id "org.jetbrains.kotlin.android" version "1.8.22" apply false
23 | }
24 |
25 | include ":app"
26 |
--------------------------------------------------------------------------------
/assets/img/FutureGraphics.kra:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/assets/img/FutureGraphics.kra
--------------------------------------------------------------------------------
/assets/img/FutureGraphics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/assets/img/FutureGraphics.png
--------------------------------------------------------------------------------
/assets/img/foreground.kra:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/assets/img/foreground.kra
--------------------------------------------------------------------------------
/assets/img/foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/assets/img/foreground.png
--------------------------------------------------------------------------------
/assets/img/icon.kra:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/assets/img/icon.kra
--------------------------------------------------------------------------------
/assets/img/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/assets/img/icon.png
--------------------------------------------------------------------------------
/assets/svg/bandsintown.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/behance.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/codepen.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/dribbble.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/dropbox.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/email.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/facebook.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/fivehundredpix.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/flickr.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/foursquare.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/google.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/google_play.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/instagram.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/itunes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/linkedin.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/mailto.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/medium.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/meetup.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/pinterest.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/rdio.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/reddit.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/rss.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/sharethis.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/smugmug.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/snapchat.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/soundcloud.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/spotify.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/squarespace.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/tumblr.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/twitch.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/twitter.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/vevo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/vimeo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/vine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/vk.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/vsco.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/wechat.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/whatsapp.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/yelp.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/youtube.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/tools/error_handling_checker.py:
--------------------------------------------------------------------------------
1 | import json
2 | import glob
3 |
4 |
5 | def in_dart(key1,key2):
6 | for file in glob.glob("lib/*.dart"):
7 | with open(file,'r',encoding="utf-8") as f:
8 | code = f.read()
9 | count = code.count(key1) - code.count(key2)
10 | if count != 0:
11 | print(f"{key1} is {count} more in {file}")
12 |
13 | for file in glob.glob("lib/*/*.dart"):
14 | with open(file,'r',encoding="utf-8") as f:
15 | code = f.read()
16 | count = code.count(key1) - code.count(key2)
17 | if count != 0:
18 | print(f"{key1} is {count} more in {file}")
19 |
20 | for file in glob.glob("lib/*/*/*.dart"):
21 | with open(file,'r',encoding="utf-8") as f:
22 | code = f.read()
23 | count = code.count(key1) - code.count(key2)
24 | if count != 0:
25 | print(f"{key1} is {count} more in {file}")
26 |
27 | in_dart("VRChatAPI(cookie","apiError")
--------------------------------------------------------------------------------
/assets/tools/l10n/checker.py:
--------------------------------------------------------------------------------
1 | import json
2 | import glob
3 |
4 | with open('lib/l10n/app_en.arb','r',encoding="utf-8") as f:
5 | json_load = json.load(f)
6 |
7 |
8 | def in_dart(key):
9 | for file in glob.glob("lib/*.dart", recursive=True):
10 | with open(file,'r',encoding="utf-8") as f:
11 | if(f"AppLocalizations.of(context)!.{key}" in f.read()):
12 | return False
13 | for file in glob.glob("lib/**/*.dart", recursive=True):
14 | with open(file,'r',encoding="utf-8") as f:
15 | if(f"AppLocalizations.of(context)!.{key}" in f.read()):
16 | return False
17 | return True
18 |
19 | for key in json_load:
20 | if key[0] == "@":
21 | continue
22 |
23 | if in_dart(key):
24 | print(f"{key} is not found")
--------------------------------------------------------------------------------
/assets/tools/l10n/marge.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 |
4 | with open('lib/l10n/app_ja.arb','r',encoding="utf-8") as f:
5 | json_load_into = json.load(f)
6 |
7 | with open('lib/l10n/app_en.arb','r',encoding="utf-8") as f:
8 | json_load_from = json.load(f)
9 |
10 | output_json = {}
11 |
12 | for key in json_load_from:
13 | if type(json_load_from[key]) is str:
14 | output_json[key] = json_load_into.get(key,json_load_from[key])
15 |
16 |
17 | with open('lib/l10n/l10n.arb', 'w+' ,encoding="utf-8") as f:
18 | json.dump(output_json, f, indent=4,ensure_ascii=False )
--------------------------------------------------------------------------------
/assets/tools/l10n/to_arb.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 |
4 | with open('lib/l10n/app_ja.arb','r',encoding="utf-8") as f:
5 | json_load = json.load(f)
6 |
7 | with open('lib/l10n/l10n.txt','r',encoding="utf-8") as f:
8 | lines = f.read().split("\n")
9 |
10 | i = 0
11 | for key in json_load:
12 | if type(json_load[key]) is str:
13 | json_load[key] = lines[i]
14 | i += 1
15 |
16 |
17 | with open('lib/l10n/l10n.arb', 'w+' ,encoding="utf-8") as f:
18 | json.dump(json_load, f, indent=4,ensure_ascii=False )
--------------------------------------------------------------------------------
/assets/tools/l10n/to_txt.py:
--------------------------------------------------------------------------------
1 | import json
2 | from tokenize import String
3 |
4 | with open('lib/l10n/app_ja.arb','r',encoding="utf-8") as f:
5 | json_load = json.load(f)
6 |
7 |
8 |
9 | output = ""
10 | for key in json_load:
11 | if type(json_load[key]) is str:
12 | output += json_load[key] + "\n"
13 |
14 |
15 | with open('lib/l10n/l10n_base.txt', mode='w+',encoding="utf-8") as f:
16 | f.write(output)
--------------------------------------------------------------------------------
/assets/tools/svg/svg.py:
--------------------------------------------------------------------------------
1 | import pathlib
2 | import json
3 |
4 | svglist = json.load(open('assets/svg/svg.json', 'r'))
5 |
6 |
7 | for key in svglist.keys():
8 | pathlib.Path("assets/svg/{0}.svg".format(key)).touch()
9 | with open("assets/svg/{0}.svg".format(key),'w') as f:
10 | f.write("""
11 |
12 |
13 |
14 | """.format(svglist[key]["icon"]))
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | flutter build apk
2 | flutter build appbundle
--------------------------------------------------------------------------------
/cspell.json:
--------------------------------------------------------------------------------
1 | {
2 | "enabled": true,
3 | "version": "0.2",
4 | "language": "en",
5 | "words": [
6 | /* Service Name */
7 | "bandsintown",
8 | "behance",
9 | "codepen",
10 | "dribbble",
11 | "fivehundredpix",
12 | "flickr",
13 | "pinterest",
14 | "rdio",
15 | "sharethis",
16 | "smugmug",
17 | "soundcloud",
18 | "squarespace",
19 | "vevo",
20 | "vrchat",
21 | "vsco",
22 | "wechat",
23 | /* Product */
24 | "Macbook",
25 | "appgallery",
26 | /* HTTP */
27 | "KHTML",
28 | /* API */
29 | "standalonewindows",
30 | "totp",
31 | "twofactorauth",
32 | "moderations",
33 | /* Flutter */
34 | "unfocus",
35 | "autofocus",
36 | "ARGB",
37 | "pubspec",
38 | /* Dart */
39 | "sublist",
40 | /* Library */
41 | "cupertino",
42 | "fluttertoast",
43 | "agconnect",
44 | "riverpod",
45 | "inappwebview",
46 | /* Name */
47 | "yuki",
48 | "Tupper",
49 | /* Other */
50 | "dont"
51 | ],
52 | "ignorePaths": [
53 | /*Flutter*/
54 | "android/**",
55 | "build/**",
56 | "ios/**",
57 | "windows/**",
58 | "pubspec.yaml",
59 | /*Extension*/
60 | "*kra",
61 | /* Other */
62 | "lib/l10n/**",
63 | "lib/api/assets/lang.dart"
64 | ]
65 | }
66 |
--------------------------------------------------------------------------------
/docs/contribute/en.md:
--------------------------------------------------------------------------------
1 | # Contribute
2 |
3 | ## About Branches
4 |
5 | - **master** Product Release Same as GooglePlay
6 | - **master-HMS** Product Release Same as AppGallery
7 | - **pre** Pre-release Major feature additions or Google Play review
8 | - **pre-HMS** Pre-release AppGallery review
9 | - **develop** Development version PullRequest goes here
10 |
11 | ## Translation
12 |
13 | - [Issues](https://github.com/fa0311/vrc_manager/issues/new?assignees=&labels=bug&template=translation-error.yml)
14 | - [lib/l10n](../../lib/l10n)
15 |
16 | ### icon
17 |
18 | The current app icon is temporary
19 | We are currently accepting applications
20 |
21 | ## Setup
22 |
23 | ```shell
24 | flutter pub get
25 | ```
26 |
27 | ## Build
28 |
29 | ```shell
30 | flutter run
31 | ```
32 |
--------------------------------------------------------------------------------
/docs/contribute/ja.md:
--------------------------------------------------------------------------------
1 | # 貢献
2 |
3 | ## ブランチについて
4 |
5 | - **master** プロダクトリリース GooglePlay と同じ
6 | - **master-HMS** プロダクトリリース AppGallery と同じ
7 | - **pre** プレリリース 大きな機能追加もしくは GooglePlay の審査
8 | - **pre-HMS** プレリリース AppGallery の審査
9 | - **develop** 開発バージョン PullRequest はここへ
10 |
11 | ## 翻訳
12 |
13 | - [Issues](https://github.com/fa0311/vrc_manager/issues/new?assignees=&labels=bug&template=translation-error.yml)
14 | - [lib/l10n](../../lib/l10n)
15 |
16 | ### アイコン
17 |
18 | 現在のアプリアイコンは仮のものです
19 | 募集中です
20 |
21 | ## セットアップ
22 |
23 | ```shell
24 | flutter pub get
25 | ```
26 |
27 | ## ビルド
28 |
29 | ```shell
30 | flutter run
31 | ```
32 |
--------------------------------------------------------------------------------
/docs/img/screenshots1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/docs/img/screenshots1.png
--------------------------------------------------------------------------------
/docs/img/screenshots2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/docs/img/screenshots2.png
--------------------------------------------------------------------------------
/docs/img/screenshots3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/docs/img/screenshots3.png
--------------------------------------------------------------------------------
/docs/img/screenshots4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/docs/img/screenshots4.png
--------------------------------------------------------------------------------
/docs/img/screenshots5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/docs/img/screenshots5.png
--------------------------------------------------------------------------------
/docs/privacy_policy/en.md:
--------------------------------------------------------------------------------
1 | # Privacy Policy.
2 |
3 | [Japanese](ja.md) / [English](en.md)
4 |
5 | # Introduction
6 |
7 | yuki0311 ("we", "us", "our") has established the following privacy policy regarding the handling of users' personal information in the services provided on various devices for smartphones and mobile devices (the "Services").
8 | In the event of any inconsistency between this Privacy Policy in Japanese and the corresponding Privacy Policy in other languages, the Japanese version shall prevail.
9 |
10 | ## Data to be collected
11 |
12 | We do not collect any information that users provide directly through the Service's content or the Service's functionality. All data entered by you through the Services will only be stored on your device. However, the Service uses third party services that may collect personal information or information that can be used to identify you.
13 |
14 | The third party services used by the Service and links to their privacy-related information are listed below.
15 |
16 | - [vrchat.com](https://hello.vrchat.com/privacy)
17 | - [github.com](https://docs.github.com/en/site-policy/privacy-policies)
18 |
19 | ## Further information on personal data
20 |
21 | The Service is not intended for children under 13 years of age. The user declares that he/she is an adult according to the applicable law. Minors may only use the Services with the support of a parent or guardian. Under no circumstances may persons under the age of 13 use the Services.
22 |
23 | ## Links to other sites
24 |
25 | The Service may contain links to other sites. When you click on a third party link, you will be taken to that site. Note that these external sites are not operated by us. We therefore strongly recommend that you review the privacy policies of these websites. We have no control over, and accept no responsibility for, the content, privacy policies or practices of any third party sites or services.
26 |
27 | ## Changes to our privacy policy
28 |
29 | We may update our Privacy Policy from time to time. The Privacy Policy is maintained on Github and we will notify you of changes when we post a new Privacy Policy on this page by enabling Notifications on Github. These changes will take effect immediately after they are posted on this page. More information about notifications can be found [here](https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications).
30 |
31 | ## Transparency of the Service
32 |
33 | All programmes of the Service are publicly available on Github.
34 | For more information, see [here](https://github.com/fa0311/vrc_manager).
35 |
36 | ## How to contact us.
37 |
38 | If you have any questions about this Privacy Policy, please contact us at the following email address.
39 |
40 | yuki@yuki0311.com
41 |
--------------------------------------------------------------------------------
/docs/privacy_policy/ja.md:
--------------------------------------------------------------------------------
1 | # プライバシーポリシー
2 |
3 | [日本語](ja.md) / [英語](en.md)
4 |
5 | # はじめに
6 |
7 | yuki0311 (以下,「私達」) は、スマートフォンおよびモバイル デバイス用のさまざまなデバイス上で提供するサービス(以下,「本サービス」)における、ユーザーの個人情報の取扱いについて以下のとおりプライバシーポリシーを定めます。
8 | この日本語のプライバシーポリシーとそれに対応する他の言語のプライバシーポリシーとに矛盾がある場合は、日本語を優先するものとします。
9 |
10 | ## 収集するデータ
11 |
12 | 私達はユーザーが本サービスのコンテンツまたは本サービスの機能を通じて直接提供する情報を収集することはありません。本サービスを通じてユーザーが入力したすべてのデータはユーザーのデバイスにのみ保存されます。ただし本サービスは個人情報もしくはあなたを識別するために使用される情報を収集する可能性のあるサードパーティのサービスを使用します。
13 |
14 | 本サービスの利用するサードパーティのサービスとそのプライバシー関連の情報へのリンクを下記で示します。
15 |
16 | - [vrchat.com](https://hello.vrchat.com/privacy)
17 | - [github.com](https://docs.github.com/en/site-policy/privacy-policies)
18 |
19 | ## 個人データに関する詳細情報
20 |
21 | 本サービスは、13 歳未満の子供を対象としていません。ユーザーは、適用される法律に従って成人であると宣言します。未成年者は親または保護者の支援がある場合にのみ本サービスを使用できます。いかなる状況においても、13 歳未満の人は本サービスを使用できません。
22 |
23 |
24 | ## 他のサイトへのリンク
25 |
26 | 本サービスには、他のサイトへのリンクが含まれている場合があります。サードパーティのリンクをクリックすると、そのサイトに移動します。これらの外部サイトは私達によって運営されていないことに注意してください。したがって、これらの Web サイトのプライバシーポリシーを確認することを強くお勧めします。当社は、第三者のサイトまたはサービスのコンテンツ、プライバシーポリシー、または慣行を管理することはできず、責任も負わないものとします。
27 |
28 | ## プライバシーポリシーの変更
29 |
30 | 私達はプライバシーポリシーを更新する場合があります。プライバシーポリシーは Github で管理されているため Github 上の Notifications を有効にすることによりこのページに新しいプライバシーポリシーを掲載する際に変更を通知します。これらの変更はこのページに掲載された直後に有効になります。通知についての詳細は[こちら](https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications)をご覧ください。
31 |
32 | ## 本サービスの透明性
33 |
34 | 本サービスのプログラムはすべて Github 上で公開されています。
35 | 詳細は[こちら](https://github.com/fa0311/vrc_manager)をご覧ください。
36 |
37 | ## お問い合わせ方法
38 |
39 | このプライバシーポリシーに関してご質問がある場合は、次のメール アドレスまでご連絡ください。
40 |
41 | yuki@yuki0311.com
42 |
--------------------------------------------------------------------------------
/docs/user_policies/en.md:
--------------------------------------------------------------------------------
1 | # User policy
2 |
3 | [日本語](ja.md) / [English](en.md)
4 |
5 | ## Introduction
6 |
7 | yuki0311 ("we", "us", "our", "we", "our") sets out the terms and conditions of use for the services provided on various devices for smartphones and mobile devices (the "Services").
8 | In the event of any inconsistency between this English privacy policy and the corresponding privacy policy in other languages, the Japanese shall prevail.
9 |
10 | ## Use of data
11 |
12 | Personal data obtained through the use of the Service is governed by the [privacy policy](../privacy_policy/en.md).
13 |
14 | ## Account and registration
15 |
16 | You must register for a third party [VRChat](https://hello.vrchat.com/) account to access most features of the Service.
17 | The Service may use [VRChat](https://hello.vrchat.com/) login credentials to access certain features of the Platform.
18 |
19 | ## Copyright
20 |
21 | Please see [MIT LICENSE](/LICENSE) for the copyright of the Service.
22 |
23 | ## Prohibitions
24 |
25 | Please see [MIT LICENSE](/LICENSE) for information on the prohibitions of the Service.
26 | In addition, the User may not engage in any conduct prohibited by the Service when using third party services.
27 |
28 | - [vrchat.com](https://hello.vrchat.com/legal)
29 |
30 | ## Disclaimer
31 |
32 | Please see [MIT LICENSE](/LICENSE) for a disclaimer of liability for the Service.
33 |
34 | ## Prohibition of transfer of rights and obligations
35 |
36 | The User may not transfer his/her position in the contract of use or his/her rights or obligations under these Terms and Conditions to a third party or offer them as security without the prior written consent of the Company.
37 |
38 | ## Governing law and jurisdiction
39 |
40 | The interpretation of these Terms and Conditions shall be governed by the laws of Japan.
41 | In the event of disputes regarding the Service, the court with jurisdiction over the location of our head office shall have exclusive jurisdiction.
42 |
43 | ## Changes to the User Policy
44 |
45 | We may update the User Policy from time to time. As the User Policy is maintained on Github, you will be notified of changes when we post a new User Policy on this page by enabling Notifications on Github. These changes will take effect immediately after they are posted on this page. More information about notifications can be found [here](https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications).
46 |
47 | ## Transparency of the Service
48 |
49 | All programmes of the Service are publicly available on Github.
50 | For more information, see [here](https://github.com/fa0311/vrc_manager).
51 |
52 | ## How to contact us
53 |
54 | If you have any questions regarding this user policy, please contact us at the following email address.
55 |
56 | yuki@yuki0311.com
57 |
--------------------------------------------------------------------------------
/docs/user_policies/ja.md:
--------------------------------------------------------------------------------
1 | # ユーザーポリシー
2 |
3 | [日本語](ja.md) / [English](en.md)
4 |
5 | ## はじめに
6 |
7 | yuki0311 (以下,「私達」) は、スマートフォンおよびモバイル デバイス用のさまざまなデバイス上で提供するサービス(以下,「本サービス」)における利用条件を定めます。
8 | この日本語のプライバシーポリシーとそれに対応する他の言語のプライバシーポリシーとに矛盾がある場合は、日本語を優先するものとします。
9 |
10 | ## データの使用
11 |
12 | 本サービスの利用によって取得する個人情報については[プライバシーポリシー](../privacy_policy/ja.md)に従い適切に取り扱うものとします。
13 |
14 | ## アカウントと登録
15 |
16 | 本サービスのほとんどの機能にアクセスするにはサードパーティの[VRChat](https://hello.vrchat.com/)のアカウントを登録する必要があります。
17 | 本サービスは[VRChat](https://hello.vrchat.com/)のログイン資格情報を使用してプラットフォームの特定の機能にアクセスすることがあります。
18 |
19 | ## 著作権
20 |
21 | 本サービスの著作権については[MIT LICENSE](/LICENSE)をご覧ください。
22 |
23 | ## 禁止事項
24 |
25 | 本サービスの禁止事項については[MIT LICENSE](/LICENSE)をご覧ください。
26 | また、ユーザーはサードパーティサービスの利用にあたりサービスが禁止している行為をしてはなりません。
27 |
28 | - [vrchat.com](https://hello.vrchat.com/legal)
29 |
30 | ## 免責事項
31 |
32 | 本サービスの免責事項については[MIT LICENSE](/LICENSE)をご覧ください。
33 |
34 | ## 権利義務の譲渡の禁止
35 |
36 | ユーザーは,当社の書面による事前の承諾なく,利用契約上の地位または本規約に基づく権利もしくは義務を第三者に譲渡し,または担保に供することはできません。
37 |
38 | ## 準拠法・裁判管轄
39 |
40 | 本規約の解釈にあたっては,日本法を準拠法とします。
41 | 本サービスに関して紛争が生じた場合には,当社の本店所在地を管轄する裁判所を専属的合意管轄とします。
42 |
43 | ## ユーザーポリシーの変更
44 |
45 | 私達はユーザーポリシーを更新する場合があります。ユーザーポリシーは Github で管理されているため Github 上の Notifications を有効にすることによりこのページに新しいユーザーポリシーを掲載する際に変更を通知します。これらの変更はこのページに掲載された直後に有効になります。通知についての詳細は[こちら](https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications)をご覧ください。
46 |
47 | ## 本サービスの透明性
48 |
49 | 本サービスのプログラムはすべて Github 上で公開されています。
50 | 詳細は[こちら](https://github.com/fa0311/vrc_manager)をご覧ください。
51 |
52 | ## お問い合わせ方法
53 |
54 | このユーザーポリシーに関してご質問がある場合は、次のメール アドレスまでご連絡ください。
55 |
56 | yuki@yuki0311.com
57 |
--------------------------------------------------------------------------------
/gen.ps1:
--------------------------------------------------------------------------------
1 | cspell **
2 | python assets/tools/l10n/checker.py
3 | flutter pub run import_sorter:main
4 | flutter gen-l10n
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '11.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | # target 'RunnerTests' do
36 | # inherit! :search_paths
37 | # end
38 | end
39 |
40 | post_install do |installer|
41 | installer.pods_project.targets.each do |target|
42 | flutter_additional_ios_build_settings(target)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CADisableMinimumFrameDurationOnPhone
6 |
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleDisplayName
10 | Vrchat Mobile Client
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | vrc_manager
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | $(FLUTTER_BUILD_NAME)
23 | CFBundleSignature
24 | ????
25 | CFBundleVersion
26 | $(FLUTTER_BUILD_NUMBER)
27 | LSApplicationQueriesSchemes
28 |
29 | https
30 |
31 | LSRequiresIPhoneOS
32 |
33 | UIApplicationSupportsIndirectInputEvents
34 |
35 | UILaunchStoryboardName
36 | LaunchScreen
37 | UIMainStoryboardFile
38 | Main
39 | UISupportedInterfaceOrientations
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationLandscapeLeft
43 | UIInterfaceOrientationLandscapeRight
44 |
45 | UISupportedInterfaceOrientations~ipad
46 |
47 | UIInterfaceOrientationPortrait
48 | UIInterfaceOrientationPortraitUpsideDown
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UIViewControllerBasedStatusBarAppearance
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/l10n.yaml:
--------------------------------------------------------------------------------
1 | arb-dir: lib/l10n
2 | template-arb-file: app_en.arb
3 | output-localization-file: app_localizations.dart
--------------------------------------------------------------------------------
/lib/api/.gitignore:
--------------------------------------------------------------------------------
1 | *.json
--------------------------------------------------------------------------------
/lib/api/assets/assets.dart:
--------------------------------------------------------------------------------
1 | class VRChatAssets {
2 | static Uri vrchat = Uri.https("vrchat.com");
3 | static Uri vrchatScheme = Uri(scheme: "vrchat");
4 | static Uri assets = Uri.https("assets.vrchat.com");
5 |
6 | // cspell:disable-next-line
7 | static String apiKey = "JlE5Jldo5Jibnk5O5hTx6XVqsJu4WJ26";
8 |
9 | static String homeTitle = "Home - VRChat";
10 | static String loginTitle = "Login - VRChat";
11 |
12 | static Uri login = VRChatAssets.vrchat.resolve("/home/login");
13 | static Uri user = VRChatAssets.vrchat.resolve("/home/user/");
14 | static Uri launch = VRChatAssets.vrchat.resolve("/home/launch");
15 | static Uri locations = VRChatAssets.vrchat.resolve("/home/locations");
16 | static Uri groups = VRChatAssets.vrchat.resolve("/home/groups");
17 | static Uri download = VRChatAssets.vrchat.resolve("/home/download");
18 | static Uri worlds = VRChatAssets.vrchat.resolve("/home/worlds/");
19 | static Uri content = VRChatAssets.vrchat.resolve("/home/content");
20 | static Uri avatars = VRChatAssets.vrchat.resolve("/home/avatars");
21 | static Uri favoritesWorlds = VRChatAssets.vrchat.resolve("/home/favorites/world/");
22 | static Uri favoritesAvatars = VRChatAssets.vrchat.resolve("/home/favorites/avatar/");
23 | // cspell:disable-next-line
24 | static Uri accountLink = VRChatAssets.vrchat.resolve("/home/accountlink");
25 | // cspell:disable-next-line
26 | static Uri playerModerations = VRChatAssets.vrchat.resolve("/home/playermoderations");
27 | static Uri messages = VRChatAssets.vrchat.resolve("/home/messages");
28 | static Uri profile = VRChatAssets.vrchat.resolve("/home/profile");
29 | static Uri search = VRChatAssets.vrchat.resolve("/home/search/");
30 |
31 | static Uri defaultPrivateImage = assets.resolve("/www/images/default_private_image.png");
32 | static Uri defaultBetweenImage = assets.resolve("/www/images/default_between_image.png");
33 | }
34 |
--------------------------------------------------------------------------------
/lib/api/assets/icon.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | enum VRChatExternalServices {
5 | none(color: 0xFF000000, text: "none"),
6 | fivehundredpix(color: 0xFF222222, text: "fivehundredpix"),
7 | bandsintown(color: 0xFF1B8793, text: "bandsintown"),
8 | behance(color: 0xFF007CFF, text: "behance"),
9 | codepen(color: 0xFF151515, text: "codepen"),
10 | dribbble(color: 0xFFea4c89, text: "dribbble"),
11 | dropbox(color: 0xFF1081DE, text: "dropbox"),
12 | email(color: 0xFF7f7f7f, text: "email"),
13 | facebook(color: 0xFF3b5998, text: "facebook"),
14 | flickr(color: 0xFF0063db, text: "flickr"),
15 | foursquare(color: 0xFF0072b1, text: "foursquare"),
16 | github(color: 0xFF4183c4, text: "github"),
17 | googlePlay(color: 0xFF40BBC1, text: "google_play"),
18 | google(color: 0xFFdd4b39, text: "google"),
19 | instagram(color: 0xFF3f729b, text: "instagram"),
20 | itunes(color: 0xFFE049D1, text: "itunes"),
21 | linkedin(color: 0xFF007fb1, text: "linkedin"),
22 | mailto(color: 0xFF7f7f7f, text: "mailto"),
23 | medium(color: 0xFF333332, text: "medium"),
24 | meetup(color: 0xFFE51937, text: "meetup"),
25 | pinterest(color: 0xFFcb2128, text: "pinterest"),
26 | rdio(color: 0xFF0475C5, text: "rdio"),
27 | reddit(color: 0xFFFF4500, text: "reddit"),
28 | rss(color: 0xFFEF8733, text: "rss"),
29 | sharethis(color: 0xFF00BF00, text: "sharethis"),
30 | smugmug(color: 0xFF8cca1e, text: "smugmug"),
31 | snapchat(color: 0xFFFFC91B, text: "snapchat"),
32 | soundcloud(color: 0xFFFF5700, text: "soundcloud"),
33 | spotify(color: 0xFF2EBD59, text: "spotify"),
34 | squarespace(color: 0xFF1C1C1C, text: "squarespace"),
35 | tumblr(color: 0xFF2c4762, text: "tumblr"),
36 | twitch(color: 0xFF6441A5, text: "twitch"),
37 | twitter(color: 0xFF00aced, text: "twitter"),
38 | vevo(color: 0xFFED1A3B, text: "vevo"),
39 | vimeo(color: 0xFF1ab7ea, text: "vimeo"),
40 | vine(color: 0xFF00BF8F, text: "vine"),
41 | vk(color: 0xFF45668e, text: "vk"),
42 | vsco(color: 0xFF83878A, text: "vsco"),
43 | wechat(color: 0xFF00c80f, text: "wechat"),
44 | whatsapp(color: 0xFF25D366, text: "whatsapp"),
45 | yelp(color: 0xFFB90C04, text: "yelp"),
46 | youtube(color: 0xFFff3333, text: "youtube");
47 |
48 | Color toColor() {
49 | return Color(color);
50 | }
51 |
52 | final int color;
53 | final String text;
54 | const VRChatExternalServices({required this.color, required this.text});
55 | }
56 |
57 | VRChatExternalServices byVrchatExternalServices(Uri uri) {
58 | for (VRChatExternalServices key in VRChatExternalServices.values) {
59 | if (uri.toString().contains(key.text)) return key;
60 | }
61 | return VRChatExternalServices.none;
62 | }
63 |
--------------------------------------------------------------------------------
/lib/api/assets/instance_type.dart:
--------------------------------------------------------------------------------
1 | enum VRChatInstanceType {
2 | public,
3 | hidden,
4 | friends,
5 | private,
6 | group;
7 | }
8 |
9 | enum VRChatInstanceIdOther {
10 | traveling,
11 | private,
12 | offline;
13 | }
14 |
--------------------------------------------------------------------------------
/lib/api/assets/lang.dart:
--------------------------------------------------------------------------------
1 | enum VRChatLanguage {
2 | eng(text: "English"),
3 | kor(text: "한국어"),
4 | rus(text: "Русский"),
5 | spa(text: "Español"),
6 | por(text: "Português"),
7 | zho(text: "中文"),
8 | deu(text: "Deutsch"),
9 | jpn(text: "日本語"),
10 | fra(text: "Français"),
11 | swe(text: "Svenska"),
12 | nld(text: "Nederlands"),
13 | pol(text: "Polski"),
14 | dan(text: "Dansk"),
15 | nor(text: "Norsk"),
16 | ita(text: "Italiano"),
17 | tha(text: "ภาษาไทย"),
18 | fin(text: "Suomi"),
19 | hun(text: "Magyar"),
20 | ces(text: "Čeština"),
21 | tur(text: "Türkçe"),
22 | ara(text: "العربية"),
23 | ron(text: "Română"),
24 | vie(text: "Tiếng Việt"),
25 | ase(text: "American Sign Language"),
26 | bfi(text: "British Sign Language"),
27 | dse(text: "Dutch Sign Language"),
28 | fsl(text: "French Sign Language"),
29 | kvk(text: "Korean Sign Language");
30 |
31 | final String text;
32 | const VRChatLanguage({required this.text});
33 | }
34 |
--------------------------------------------------------------------------------
/lib/api/assets/region.dart:
--------------------------------------------------------------------------------
1 | // Project imports:
2 | import 'package:vrc_manager/api/assets/assets.dart';
3 |
4 | enum VRChatRegion {
5 | us(text: "/www/images/Region_US.png"),
6 | use(text: "/www/images/Region_US.png"),
7 | eu(text: "/www/images/Region_EU.png"),
8 | jp(text: "/www/images/Region_JP.png");
9 |
10 | final String text;
11 | Uri toUri() {
12 | return VRChatAssets.assets.resolve(text);
13 | }
14 |
15 | const VRChatRegion({required this.text});
16 | }
17 |
--------------------------------------------------------------------------------
/lib/api/assets/status.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | enum VRChatStatusData {
5 | active(text: "active", color: 0xFF51e57e),
6 | joinMe(text: "join me", color: 0xFF42CAFF),
7 | busy(text: "busy", color: 0xFF5b0b0b),
8 | askMe(text: "ask me", color: 0xFFe88134),
9 | offline(text: "offline", color: 0xFF808080);
10 |
11 | Color toColor() {
12 | return Color(color);
13 | }
14 |
15 | final String text;
16 | final int color;
17 | const VRChatStatusData({required this.text, required this.color});
18 | }
19 |
20 | VRChatStatusData byVrchatStatusData(String text) {
21 | for (VRChatStatusData status in VRChatStatusData.values) {
22 | if (text == status.text) return status;
23 | }
24 | return VRChatStatusData.offline;
25 | }
26 |
--------------------------------------------------------------------------------
/lib/api/data_class_ext.dart:
--------------------------------------------------------------------------------
1 | // Project imports:
2 | import 'package:vrc_manager/api/data_class.dart';
3 |
4 | class VRChatWorldInstance {
5 | final VRChatWorld _world;
6 | final VRChatInstance _instance;
7 |
8 | VRChatWorld get world => _world;
9 | VRChatInstance get instance => _instance;
10 |
11 | VRChatWorldInstance(this._world, this._instance);
12 | }
13 |
14 | class VRChatUserFriendsStatus {
15 | final VRChatUser _user;
16 | final VRChatFriendStatus _status;
17 |
18 | VRChatUser get user => _user;
19 | VRChatFriendStatus get status => _status;
20 |
21 | VRChatUserFriendsStatus(this._user, this._status);
22 | }
23 |
--------------------------------------------------------------------------------
/lib/assets.dart:
--------------------------------------------------------------------------------
1 | class Assets {
2 | static Uri svg = Uri.directory("assets/svg/");
3 | // cspell:disable-next-line
4 | static String charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
5 |
6 | static String userAgentBase = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36";
7 | static String userAgent(String version) => '$userAgentBase VRCManager/$version ($repository)';
8 |
9 | static Uri github = Uri.https("github.com");
10 | static Uri twitter = Uri.https("twitter.com");
11 | static Uri googlePlay = Uri.https("play.google.com");
12 |
13 | static Uri repository = Assets.github.resolve("/fa0311/vrc_manager");
14 | static Uri issues = Assets.github.resolve("/fa0311/vrc_manager/issues/new/choose");
15 | static Uri contact = Assets.twitter.resolve("/faa0311");
16 | static Uri rate = Assets.googlePlay.replace(path: "/store/apps/details", queryParameters: {"id": "com.yuki0311.vrc_manager"});
17 | static Uri release = Assets.github.resolve("/fa0311/vrc_manager/releases");
18 | static Uri report = Assets.github.replace(path: "/fa0311/vrc_manager/issues/new", queryParameters: {"template": "redirected-from-app.yml"});
19 | static Uri userPolicy = Assets.github.resolve("/fa0311/vrc_manager/blob/master/docs/user_policies/ja.md");
20 | }
21 |
--------------------------------------------------------------------------------
/lib/assets/api/get.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 |
3 | // Project imports:
4 | import 'package:vrc_manager/api/assets/instance_type.dart';
5 | import 'package:vrc_manager/api/data_class.dart';
6 | import 'package:vrc_manager/api/main.dart';
7 | import 'package:vrc_manager/main.dart';
8 | import 'package:vrc_manager/scenes/setting/logger.dart';
9 |
10 | Future getWorld({
11 | required VRChatAPI vrchatLoginSession,
12 | required VRChatFriends user,
13 | required Map locationMap,
14 | }) async {
15 | try {
16 | String wid = user.location.split(":")[0];
17 | if (VRChatInstanceIdOther.values.any((id) => id.name == user.location) || locationMap.containsKey(wid)) return;
18 | locationMap[wid] = null;
19 | locationMap[wid] = await vrchatLoginSession.worlds(wid);
20 | } catch (e, trace) {
21 | logger.e(getMessage(e), error: e, stackTrace: trace);
22 | }
23 | }
24 |
25 | Future getWorldFromFavorite({
26 | required VRChatAPI vrchatLoginSession,
27 | required VRChatFavoriteGroup favoriteGroup,
28 | required Map locationMap,
29 | }) async {
30 | try {
31 | String wid = favoriteGroup.id;
32 | if (VRChatInstanceIdOther.values.any((id) => id.name == wid) || locationMap.containsKey(wid)) return;
33 | locationMap[wid] = null;
34 | locationMap[wid] = await vrchatLoginSession.worlds(wid);
35 | } catch (e, trace) {
36 | logger.e(getMessage(e), error: e, stackTrace: trace);
37 | }
38 | }
39 |
40 | Future getInstance({
41 | required VRChatAPI vrchatLoginSession,
42 | required VRChatFriends user,
43 | required Map instanceMap,
44 | }) async {
45 | try {
46 | if (VRChatInstanceIdOther.values.any((id) => id.name == user.location) || instanceMap.containsKey(user.location)) return;
47 | instanceMap[user.location] = null;
48 | instanceMap[user.location] = await vrchatLoginSession.instances(user.location);
49 | } catch (e, trace) {
50 | logger.e(getMessage(e), error: e, stackTrace: trace);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/assets/api/post.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 |
3 | // Project imports:
4 | import 'package:vrc_manager/api/data_class.dart';
5 | import 'package:vrc_manager/api/main.dart';
6 | import 'package:vrc_manager/main.dart';
7 |
8 | Future delete({
9 | required VRChatAPI vrchatLoginSession,
10 | required VRChatFavoriteWorld world,
11 | required List favoriteWorld,
12 | }) async {
13 | try {
14 | await vrchatLoginSession.deleteFavorites(world.favoriteId);
15 | favoriteWorld.remove(world);
16 | } catch (e) {
17 | logger.e(e);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/assets/conditions.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/lib/assets/conditions.dart
--------------------------------------------------------------------------------
/lib/assets/date.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
6 | import 'package:intl/intl.dart';
7 |
8 | String generalDateDifference(BuildContext context, DateTime time) {
9 | final Duration difference = DateTime.now().difference(time);
10 | if (difference.inDays > 7) return DateFormat.yMMMMd(AppLocalizations.of(context)!.localeName).format(time);
11 | if (difference.inDays > 0) return AppLocalizations.of(context)!.dateFormat1(difference.inDays, difference.inHours % 24);
12 | if (difference.inHours > 0) return AppLocalizations.of(context)!.dateFormat2(difference.inHours, difference.inMinutes % 60);
13 | if (difference.inMinutes > 0) return AppLocalizations.of(context)!.dateFormat3(difference.inMinutes);
14 | return AppLocalizations.of(context)!.dateFormat4(difference.inSeconds);
15 | }
16 |
--------------------------------------------------------------------------------
/lib/assets/flutter/text_stream.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:io';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 | // Package imports:
7 | import 'package:flutter_sharing_intent/flutter_sharing_intent.dart';
8 | import 'package:flutter_sharing_intent/model/sharing_file.dart';
9 | // Project imports:
10 | import 'package:vrc_manager/assets/flutter/url_parser.dart';
11 |
12 | textStream({required BuildContext context, required bool forceExternal}) async {
13 | if (!Platform.isAndroid && !Platform.isIOS) return;
14 | await for (final file in FlutterSharingIntent().getMediaStream()) {
15 | for (final SharedFile sharedFile in file) {
16 | if (sharedFile.type == SharedMediaType.TEXT || sharedFile.type == SharedMediaType.URL) {
17 | String text = sharedFile.value!;
18 | Widget? value = await urlParser(url: Uri.parse(text), forceExternal: forceExternal);
19 | if (value == null) return;
20 | Navigator.of(context).popUntil((route) => route.isFirst);
21 | Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => value));
22 | }
23 | }
24 | }
25 | }
26 |
27 | Future initTest() async {
28 | final sharedFile = await FlutterSharingIntent().getInitialSharing();
29 | for (final SharedFile sharedFile in sharedFile) {
30 | if (sharedFile.type == SharedMediaType.TEXT || sharedFile.type == SharedMediaType.URL) {
31 | String text = sharedFile.value!;
32 | return text;
33 | }
34 | }
35 | return null;
36 | }
37 |
--------------------------------------------------------------------------------
/lib/assets/flutter/url_parser.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Project imports:
5 | import 'package:vrc_manager/scenes/core/splash.dart';
6 | import 'package:vrc_manager/scenes/sub/user.dart';
7 | import 'package:vrc_manager/scenes/sub/world.dart';
8 | import 'package:vrc_manager/widgets/share.dart';
9 |
10 | Future urlParser({required Uri url, required bool forceExternal}) async {
11 | final List path = url.path.split("/");
12 | final Map queryParameters = url.queryParameters;
13 | if (path.length < 2) {
14 | return null;
15 | } else if (path[2] == "launch") {
16 | return VRChatMobileSplash(child: VRChatMobileWorld(worldId: queryParameters["worldId"] ?? ""));
17 | } else if (path[2] == "world") {
18 | return VRChatMobileSplash(child: VRChatMobileWorld(worldId: path[3]));
19 | } else if (path[2] == "user") {
20 | return VRChatMobileSplash(child: VRChatMobileUser(userId: path[3]));
21 | } else {
22 | return await openInBrowser(url: url, forceExternal: forceExternal);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/assets/license.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:package_info_plus/package_info_plus.dart';
6 |
7 | Future showLicense(BuildContext context) async {
8 | final PackageInfo info = await PackageInfo.fromPlatform();
9 |
10 | showLicensePage(
11 | context: context,
12 | applicationName: info.appName,
13 | applicationVersion: info.version,
14 | applicationLegalese: '2022 yuki',
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/lib/assets/session.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:convert';
3 | import 'dart:io';
4 |
5 | // Package imports:
6 | import 'package:http/http.dart' as http;
7 |
8 | class Session {
9 | Map headers = {
10 | 'cookie': '',
11 | 'user-agent': '',
12 | };
13 |
14 | Future get(Uri url) async {
15 | http.Response response = await http.get(url, headers: headers);
16 | if (response.statusCode != 200) throw HttpException(response.body, uri: url);
17 | final dynamic body = json.decode(response.body);
18 | updateCookie(response);
19 | return body;
20 | }
21 |
22 | Future basic(Uri url, String username, String password) async {
23 | final headersAuth = Map.from(headers)
24 | ..addAll(
25 | {
26 | 'authorization': 'Basic ${base64Encode(utf8.encode('$username:$password'))}',
27 | },
28 | );
29 | http.Response response = await http.get(url, headers: headersAuth);
30 | if (response.statusCode != 200) throw HttpException(response.body, uri: url);
31 | final dynamic body = json.decode(response.body);
32 | updateCookie(response);
33 | return body;
34 | }
35 |
36 | Future post(Uri url, [Object? data]) async {
37 | http.Response response = await http.post(url, body: data ?? {}, headers: headers);
38 | if (response.statusCode != 200) throw HttpException(response.body, uri: url);
39 | final dynamic body = json.decode(response.body);
40 | updateCookie(response);
41 | return body;
42 | }
43 |
44 | Future put(Uri url, [Object? data]) async {
45 | http.Response response = await http.put(url, body: data ?? {}, headers: headers);
46 | if (response.statusCode != 200) throw HttpException(response.body, uri: url);
47 | final dynamic body = json.decode(response.body);
48 | updateCookie(response);
49 | return body;
50 | }
51 |
52 | Future delete(Uri url, [Object? data]) async {
53 | http.Response response = await http.delete(url, body: data ?? {}, headers: headers);
54 | if (response.statusCode != 200) throw HttpException(response.body, uri: url);
55 | final dynamic body = json.decode(response.body);
56 | updateCookie(response);
57 | return body;
58 | }
59 |
60 | updateCookie(http.Response response) {
61 | String? rawCookie = response.headers['set-cookie'];
62 | if (rawCookie != null) {
63 | Map cookieMap = decodeCookie(headers['cookie'] ?? "");
64 | cookieMap.addAll(decodeCookie(rawCookie));
65 | headers['cookie'] = encodeCookie(cookieMap);
66 | }
67 | }
68 |
69 | String encodeCookie(Map cookieMap) {
70 | String rawCookie = "";
71 | for (String key in cookieMap.keys) {
72 | rawCookie += "$key=${cookieMap[key]}; ";
73 | }
74 | return rawCookie;
75 | }
76 |
77 | Map decodeCookie(String rawCookie) {
78 | Map cookieMap = {};
79 | for (String row in rawCookie.split(';')) {
80 | List data = row.trim().replaceFirst('HttpOnly,', '').split('=');
81 | if (!row.contains('=')) continue;
82 | if (["Max-Age", "Path", "Expires"].contains(data[0])) continue;
83 | cookieMap[data[0]] = data[1];
84 | }
85 | return cookieMap;
86 | }
87 |
88 | String getCookie() {
89 | return headers['cookie'] ?? "";
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/assets/sort/users.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:convert';
3 |
4 | // Project imports:
5 | import 'package:vrc_manager/api/assets/instance_type.dart';
6 | import 'package:vrc_manager/api/data_class.dart';
7 | import 'package:vrc_manager/storage/grid_modal.dart';
8 | import 'package:vrc_manager/widgets/grid_modal/config.dart';
9 |
10 | List sortUsers(GridConfigNotifier config, List userList) {
11 | switch (config.sortMode) {
12 | case SortMode.name:
13 | sortByNameFromUser(userList);
14 | break;
15 | case SortMode.lastLogin:
16 | sortByLastLoginFromUser(userList);
17 | break;
18 | case SortMode.friendsInInstance:
19 | sortByLocationMapFromUser(userList);
20 | break;
21 | default:
22 | break;
23 | }
24 | if (config.descending) {
25 | return userList.reversed.toList();
26 | } else {
27 | return userList;
28 | }
29 | }
30 |
31 | Map numberOfFriendsInLocation(List userList) {
32 | Map inLocation = {};
33 | for (VRChatUser user in userList) {
34 | String location = user.location;
35 | inLocation[location] = (inLocation[location] ?? 0) + 1;
36 | }
37 | return inLocation;
38 | }
39 |
40 | sortByLocationMapFromUser(List userList) {
41 | Map inLocation = numberOfFriendsInLocation(userList);
42 | userList.sort((userA, userB) {
43 | String locationA = userA.location;
44 | String locationB = userB.location;
45 | if (locationA == locationB) return 0;
46 | if (locationA == VRChatInstanceIdOther.offline.name) return 1;
47 | if (locationB == VRChatInstanceIdOther.offline.name) return -1;
48 | if (locationA == VRChatInstanceIdOther.private.name) return 1;
49 | if (locationB == VRChatInstanceIdOther.private.name) return -1;
50 | if (locationA == VRChatInstanceIdOther.traveling.name) return 1;
51 | if (locationB == VRChatInstanceIdOther.traveling.name) return -1;
52 | if (inLocation[locationA]! > inLocation[locationB]!) return -1;
53 | if (inLocation[locationA]! < inLocation[locationB]!) return 1;
54 |
55 | List userBytesA = utf8.encode(locationA);
56 | List userBytesB = utf8.encode(locationB);
57 |
58 | for (int i = 0; i < userBytesA.length && i < userBytesB.length; i++) {
59 | if (userBytesA[i] < userBytesB[i]) return -1;
60 | if (userBytesA[i] > userBytesB[i]) return 1;
61 | }
62 | if (userBytesA.length < userBytesB.length) return -1;
63 | if (userBytesA.length > userBytesB.length) return 1;
64 | return 0;
65 | });
66 | }
67 |
68 | sortByNameFromUser(List userList) {
69 | userList.sort((userA, userB) {
70 | List userBytesA = utf8.encode(userA.displayName.toLowerCase());
71 | List userBytesB = utf8.encode(userB.displayName.toLowerCase());
72 | for (int i = 0; i < userBytesA.length && i < userBytesB.length; i++) {
73 | if (userBytesA[i] < userBytesB[i]) return -1;
74 | if (userBytesA[i] > userBytesB[i]) return 1;
75 | }
76 | if (userBytesA.length < userBytesB.length) return -1;
77 | if (userBytesA.length > userBytesB.length) return 1;
78 | return 0;
79 | });
80 | }
81 |
82 | sortByLastLoginFromUser(List userList) {
83 | userList.sort((userA, userB) {
84 | if (userA.lastLogin == null) return 1;
85 | if (userB.lastLogin == null) return -1;
86 | if (userA.lastLogin!.millisecondsSinceEpoch > userB.lastLogin!.millisecondsSinceEpoch) return -1;
87 | if (userA.lastLogin!.millisecondsSinceEpoch < userB.lastLogin!.millisecondsSinceEpoch) return 1;
88 | return 0;
89 | });
90 | }
91 |
--------------------------------------------------------------------------------
/lib/assets/sort/worlds.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:convert';
3 |
4 | // Project imports:
5 | import 'package:vrc_manager/api/data_class.dart';
6 | import 'package:vrc_manager/storage/grid_modal.dart';
7 | import 'package:vrc_manager/widgets/grid_modal/config.dart';
8 |
9 | List sortWorlds(GridConfigNotifier config, List worldList) {
10 | switch (config.sortMode) {
11 | case SortMode.name:
12 | sortByNameFromWorlds(worldList);
13 | break;
14 | case SortMode.updatedDate:
15 | sortByUpdatedDateFromWorlds(worldList);
16 | break;
17 | case SortMode.labsPublicationDate:
18 | sortByLabsPublicationDateFromWorlds(worldList);
19 | break;
20 | case SortMode.heat:
21 | sortByHeatFavoriteFromWorlds(worldList);
22 | break;
23 | case SortMode.capacity:
24 | sortByCapacityFromWorlds(worldList);
25 | break;
26 | case SortMode.occupants:
27 | sortByOccupantsFromWorlds(worldList);
28 | break;
29 | default:
30 | break;
31 | }
32 | if (config.descending) {
33 | return worldList.reversed.toList();
34 | } else {
35 | return worldList;
36 | }
37 | }
38 |
39 | sortByNameFromWorlds(List worldList) {
40 | worldList.sort((userA, userB) {
41 | List userBytesA = utf8.encode(userA.name);
42 | List userBytesB = utf8.encode(userB.name);
43 | for (int i = 0; i < userBytesA.length && i < userBytesB.length; i++) {
44 | if (userBytesA[i] < userBytesB[i]) return -1;
45 | if (userBytesA[i] > userBytesB[i]) return 1;
46 | }
47 | if (userBytesA.length < userBytesB.length) return -1;
48 | if (userBytesA.length > userBytesB.length) return 1;
49 | return 0;
50 | });
51 | }
52 |
53 | sortByUpdatedDateFromWorlds(List worldList) {
54 | worldList.sort((userA, userB) {
55 | if (userA.updatedAt.millisecondsSinceEpoch > userB.updatedAt.millisecondsSinceEpoch) return -1;
56 | if (userA.updatedAt.millisecondsSinceEpoch < userB.updatedAt.millisecondsSinceEpoch) return 1;
57 | return 0;
58 | });
59 | }
60 |
61 | sortByLabsPublicationDateFromWorlds(List worldList) {
62 | worldList.sort((userA, userB) {
63 | if (userA.labsPublicationDate == null) return 1;
64 | if (userB.labsPublicationDate == null) return -1;
65 | if (userA.labsPublicationDate!.millisecondsSinceEpoch > userB.labsPublicationDate!.millisecondsSinceEpoch) return -1;
66 | if (userA.labsPublicationDate!.millisecondsSinceEpoch < userB.labsPublicationDate!.millisecondsSinceEpoch) return 1;
67 | return 0;
68 | });
69 | }
70 |
71 | sortByHeatFavoriteFromWorlds(List worldList) {
72 | worldList.sort((userA, userB) {
73 | if (userA.heat > userB.heat) return -1;
74 | if (userA.heat < userB.heat) return 1;
75 | return 0;
76 | });
77 | }
78 |
79 | sortByCapacityFromWorlds(List worldList) {
80 | worldList.sort((userA, userB) {
81 | if (userA.capacity > userB.capacity) return -1;
82 | if (userA.capacity < userB.capacity) return 1;
83 | return 0;
84 | });
85 | }
86 |
87 | sortByOccupantsFromWorlds(List worldList) {
88 | worldList.sort((userA, userB) {
89 | if (userA.occupants > userB.occupants) return -1;
90 | if (userA.occupants < userB.occupants) return 1;
91 | return 0;
92 | });
93 | }
94 |
--------------------------------------------------------------------------------
/lib/assets/storage.dart:
--------------------------------------------------------------------------------
1 | // Package imports:
2 | import 'package:flutter_secure_storage/flutter_secure_storage.dart';
3 | import 'package:shared_preferences/shared_preferences.dart';
4 |
5 | // Project imports:
6 | import 'package:vrc_manager/main.dart';
7 | import 'package:vrc_manager/scenes/setting/logger.dart';
8 |
9 | Future getLoginSession(String key, String id) async {
10 | try {
11 | const FlutterSecureStorage storage = FlutterSecureStorage();
12 | return await storage.read(key: "$key$id");
13 | } catch (e, trace) {
14 | logger.w(getMessage(e), error: e, stackTrace: trace);
15 | return null;
16 | }
17 | }
18 |
19 | Future setLoginSession(String key, String value, String id) async {
20 | try {
21 | const FlutterSecureStorage storage = FlutterSecureStorage();
22 | return await storage.write(key: "$key$id", value: value);
23 | } catch (e, trace) {
24 | logger.w(getMessage(e), error: e, stackTrace: trace);
25 | }
26 | }
27 |
28 | Future removeLoginSession(String key, String id) async {
29 | try {
30 | const FlutterSecureStorage storage = FlutterSecureStorage();
31 | return await storage.delete(key: "$key$id");
32 | } catch (e, trace) {
33 | logger.w(getMessage(e), error: e, stackTrace: trace);
34 | }
35 | }
36 |
37 | Future getStorage(String key, {String id = ""}) async {
38 | try {
39 | final SharedPreferences storage = await SharedPreferences.getInstance();
40 | return storage.getString("$key$id");
41 | } catch (e, trace) {
42 | logger.w(getMessage(e), error: e, stackTrace: trace);
43 | return null;
44 | }
45 | }
46 |
47 | Future setStorage(String key, String value, {String id = ""}) async {
48 | try {
49 | final SharedPreferences storage = await SharedPreferences.getInstance();
50 | return await storage.setString("$key$id", value);
51 | } catch (e, trace) {
52 | logger.w(getMessage(e), error: e, stackTrace: trace);
53 | return false;
54 | }
55 | }
56 |
57 | Future removeStorage(String key, {String id = ""}) async {
58 | try {
59 | final SharedPreferences storage = await SharedPreferences.getInstance();
60 | return await storage.remove("$key$id");
61 | } catch (e, trace) {
62 | logger.w(getMessage(e), error: e, stackTrace: trace);
63 | return false;
64 | }
65 | }
66 |
67 | Future> getStorageList(String key, {String id = ""}) async {
68 | try {
69 | final SharedPreferences storage = await SharedPreferences.getInstance();
70 | return storage.getStringList("$key$id") ?? [];
71 | } catch (e, trace) {
72 | logger.w(getMessage(e), error: e, stackTrace: trace);
73 | return [];
74 | }
75 | }
76 |
77 | Future setStorageList(String key, List value, {String id = ""}) async {
78 | try {
79 | final SharedPreferences storage = await SharedPreferences.getInstance();
80 | return await storage.setStringList("$key$id", value);
81 | } catch (e, trace) {
82 | logger.w(getMessage(e), error: e, stackTrace: trace);
83 | return false;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/lib/assets/theme/enum.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
6 |
7 | // Project imports:
8 | import 'package:vrc_manager/assets/theme/true_black.dart';
9 |
10 | enum ThemeBrightness {
11 | light,
12 | dark,
13 | black,
14 | trueBlack,
15 | highContrastLight,
16 | highContrastDark;
17 |
18 | String toLocalization(BuildContext context) {
19 | switch (this) {
20 | case ThemeBrightness.light:
21 | return AppLocalizations.of(context)!.lightTheme;
22 | case ThemeBrightness.dark:
23 | return AppLocalizations.of(context)!.darkTheme;
24 | case ThemeBrightness.black:
25 | return AppLocalizations.of(context)!.blackTheme;
26 | case ThemeBrightness.trueBlack:
27 | return AppLocalizations.of(context)!.trueBlackTheme;
28 | case ThemeBrightness.highContrastLight:
29 | return AppLocalizations.of(context)!.highContrastLightTheme;
30 | case ThemeBrightness.highContrastDark:
31 | return AppLocalizations.of(context)!.highContrastDarkTheme;
32 | }
33 | }
34 |
35 | ThemeData toTheme() {
36 | switch (this) {
37 | case ThemeBrightness.light:
38 | return ThemeData(brightness: Brightness.light);
39 | case ThemeBrightness.dark:
40 | return ThemeData(brightness: Brightness.dark, primarySwatch: Colors.grey);
41 | case ThemeBrightness.black:
42 | return blackTheme();
43 | case ThemeBrightness.trueBlack:
44 | return trueBlackTheme();
45 | case ThemeBrightness.highContrastLight:
46 | return highContrastLightTheme();
47 | case ThemeBrightness.highContrastDark:
48 | return highContrastDarkTheme();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/assets/theme/true_black.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | ThemeData blackTheme() {
5 | Color black = const Color.fromARGB(255, 0, 0, 0);
6 | Color grey = const Color.fromARGB(255, 20, 20, 20);
7 | return ThemeData(
8 | brightness: Brightness.dark,
9 | canvasColor: grey,
10 | cardColor: grey,
11 | dialogBackgroundColor: black,
12 | primaryColor: black,
13 | primaryColorDark: black,
14 | primaryColorLight: black,
15 | scaffoldBackgroundColor: black,
16 | secondaryHeaderColor: black,
17 | appBarTheme: AppBarTheme(color: grey),
18 | bottomAppBarTheme: BottomAppBarTheme(color: black),
19 | colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.grey, brightness: Brightness.dark).copyWith(background: black),
20 | );
21 | }
22 |
23 | ThemeData trueBlackTheme() {
24 | Color black = const Color.fromARGB(255, 0, 0, 0);
25 | return ThemeData(
26 | brightness: Brightness.dark,
27 | canvasColor: black,
28 | cardColor: black,
29 | dialogBackgroundColor: black,
30 | highlightColor: const Color.fromARGB(150, 20, 20, 20),
31 | primaryColor: black,
32 | primaryColorDark: black,
33 | primaryColorLight: black,
34 | scaffoldBackgroundColor: black,
35 | secondaryHeaderColor: black,
36 | splashColor: const Color.fromARGB(255, 20, 20, 20),
37 | appBarTheme: AppBarTheme(color: black),
38 | bottomAppBarTheme: BottomAppBarTheme(color: black),
39 | colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.grey, brightness: Brightness.dark).copyWith(background: black),
40 | );
41 | }
42 |
43 | ThemeData highContrastLightTheme() {
44 | return ThemeData(
45 | brightness: Brightness.light,
46 | colorScheme: const ColorScheme.highContrastLight(),
47 | );
48 | }
49 |
50 | ThemeData highContrastDarkTheme() {
51 | return ThemeData(
52 | brightness: Brightness.dark,
53 | colorScheme: const ColorScheme.highContrastDark(),
54 | );
55 | }
56 |
--------------------------------------------------------------------------------
/lib/l10n/code.dart:
--------------------------------------------------------------------------------
1 | enum LanguageCode {
2 | en("English"),
3 | ja("日本語"),
4 | es("Español"),
5 | pt("Português"),
6 | ru("Pусский"),
7 | th("ไทย"),
8 | zh("简体中文");
9 |
10 | final String text;
11 | const LanguageCode(this.text);
12 | }
13 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/foundation.dart';
3 | import 'package:flutter/material.dart';
4 | // Package imports:
5 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
6 | import 'package:flutter_localizations/flutter_localizations.dart';
7 | import 'package:flutter_riverpod/flutter_riverpod.dart';
8 | import 'package:logger/logger.dart';
9 | // Project imports:
10 | import 'package:vrc_manager/scenes/core/splash.dart';
11 | import 'package:vrc_manager/scenes/setting/logger.dart';
12 | import 'package:vrc_manager/storage/accessibility.dart';
13 |
14 | ConsoleOutputExt loggerOutput = ConsoleOutputExt();
15 | Logger logger = LoggerExt(
16 | filter: ProductionFilter(),
17 | printer: PrettyPrinter(methodCount: 8),
18 | output: loggerOutput,
19 | level: kDebugMode ? Level.trace : Level.warning,
20 | );
21 |
22 | main() {
23 | runApp(const ProviderScope(child: VRChatMobile()));
24 | }
25 |
26 | class VRChatMobile extends ConsumerWidget {
27 | const VRChatMobile({super.key});
28 |
29 | @override
30 | Widget build(BuildContext context, WidgetRef ref) {
31 | AccessibilityConfigNotifier accessibilityConfig = ref.watch(accessibilityConfigProvider);
32 |
33 | return MaterialApp(
34 | title: 'VRChat Mobile Client',
35 | debugShowCheckedModeBanner: false,
36 | localizationsDelegates: const [
37 | AppLocalizations.delegate,
38 | GlobalMaterialLocalizations.delegate,
39 | GlobalWidgetsLocalizations.delegate,
40 | GlobalCupertinoLocalizations.delegate,
41 | ],
42 | supportedLocales: AppLocalizations.supportedLocales,
43 | locale: Locale(accessibilityConfig.languageCode.name, ''),
44 | theme: accessibilityConfig.themeBrightness.toTheme(),
45 | darkTheme: accessibilityConfig.darkThemeBrightness.toTheme(),
46 | home: const VRChatMobileSplash(),
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/scenes/main/friend_request.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 | // Package imports:
4 | import 'package:flutter_riverpod/flutter_riverpod.dart';
5 | // Project imports:
6 | import 'package:vrc_manager/api/data_class.dart';
7 | import 'package:vrc_manager/api/main.dart';
8 | import 'package:vrc_manager/main.dart';
9 | import 'package:vrc_manager/scenes/core/splash.dart';
10 | import 'package:vrc_manager/scenes/setting/logger.dart';
11 | import 'package:vrc_manager/widgets/grid_modal/config.dart';
12 | import 'package:vrc_manager/widgets/grid_view/extraction/render_grid/user.dart';
13 | import 'package:vrc_manager/widgets/loading.dart';
14 | import 'package:vrc_manager/widgets/scroll.dart';
15 |
16 | class VRChatMobileFriendRequestData {
17 | List userList;
18 | VRChatMobileFriendRequestData({required this.userList});
19 | }
20 |
21 | final vrchatMobileFriendsRequestProvider = FutureProvider((ref) async {
22 | VRChatAPI vrchatLoginSession = VRChatAPI(
23 | cookie: ref.watch(accountConfigProvider).loggedAccount?.cookie ?? "",
24 | userAgent: ref.watch(accountConfigProvider).userAgent,
25 | logger: logger,
26 | );
27 | List futureList = [];
28 | List userList = [];
29 | int len;
30 | try {
31 | do {
32 | int offset = futureList.length;
33 | List notify = await vrchatLoginSession.notifications(type: "friendRequest", offset: offset);
34 | for (VRChatNotifications requestUser in notify) {
35 | futureList.add(vrchatLoginSession.users(requestUser.senderUserId).then((VRChatUser user) {
36 | userList.add(user);
37 | }).catchError((e, trace) {
38 | logger.e(getMessage(e), error: e, stackTrace: trace);
39 | }));
40 | }
41 | len = notify.length;
42 | } while (len > 0);
43 | } catch (e, trace) {
44 | logger.e(getMessage(e), error: e, stackTrace: trace);
45 | }
46 | await Future.wait(futureList);
47 | return VRChatMobileFriendRequestData(userList: userList);
48 | });
49 |
50 | class VRChatMobileFriendRequest extends ConsumerWidget {
51 | const VRChatMobileFriendRequest({super.key});
52 |
53 | @override
54 | Widget build(BuildContext context, WidgetRef ref) {
55 | AsyncValue data = ref.watch(vrchatMobileFriendsRequestProvider);
56 | VRChatFriendStatus status = VRChatFriendStatus(isFriend: false, incomingRequest: true, outgoingRequest: false);
57 |
58 | return data.when(
59 | loading: () => const Loading(),
60 | error: (e, trace) {
61 | logger.w(getMessage(e), error: e, stackTrace: trace);
62 | return ScrollWidget(
63 | onRefresh: () => ref.refresh(vrchatMobileFriendsRequestProvider.future),
64 | child: ErrorPage(loggerReport: ref.read(loggerReportProvider)),
65 | );
66 | },
67 | data: (data) => ScrollWidget(
68 | onRefresh: () => ref.refresh(vrchatMobileFriendsRequestProvider.future),
69 | child: ExtractionUser(id: GridModalConfigType.favoriteWorlds, userList: data.userList, status: status),
70 | ),
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/scenes/setting/accessibility.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:io';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 | // Package imports:
7 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
8 | import 'package:flutter_riverpod/flutter_riverpod.dart';
9 | // Project imports:
10 | import 'package:vrc_manager/storage/accessibility.dart';
11 | import 'package:vrc_manager/widgets/config_modal/locale.dart';
12 | import 'package:vrc_manager/widgets/config_modal/theme.dart';
13 | import 'package:vrc_manager/widgets/modal.dart';
14 |
15 | class VRChatMobileSettingsAccessibility extends ConsumerWidget {
16 | const VRChatMobileSettingsAccessibility({super.key});
17 |
18 | @override
19 | Widget build(BuildContext context, WidgetRef ref) {
20 | AccessibilityConfigNotifier accessibilityConfig = ref.watch(accessibilityConfigProvider);
21 | return Scaffold(
22 | appBar: AppBar(
23 | title: Text(AppLocalizations.of(context)!.setting),
24 | ),
25 | body: SafeArea(
26 | child: SingleChildScrollView(
27 | child: Container(
28 | padding: const EdgeInsets.only(top: 10),
29 | child: Column(
30 | children: [
31 | ListTile(
32 | title: Text(AppLocalizations.of(context)!.language),
33 | subtitle: Text(accessibilityConfig.languageCode.text),
34 | onTap: () => showModalBottomSheetStatelessWidget(
35 | context: context,
36 | builder: () => const LocaleModal(),
37 | ),
38 | ),
39 | ListTile(
40 | title: Text(AppLocalizations.of(context)!.deviceLightTheme),
41 | subtitle: Text(accessibilityConfig.themeBrightness.toLocalization(context)),
42 | onTap: () => showModalBottomSheetStatelessWidget(
43 | context: context,
44 | builder: () => const ThemeBrightnessModal(dark: false),
45 | ),
46 | ),
47 | ListTile(
48 | title: Text(AppLocalizations.of(context)!.deviceDarkTheme),
49 | subtitle: Text(accessibilityConfig.darkThemeBrightness.toLocalization(context)),
50 | onTap: () => showModalBottomSheetStatelessWidget(
51 | context: context,
52 | builder: () => const ThemeBrightnessModal(dark: true),
53 | ),
54 | ),
55 | if (!Platform.isWindows)
56 | SwitchListTile(
57 | value: accessibilityConfig.forceExternalBrowser,
58 | title: Text(AppLocalizations.of(context)!.forceExternalBrowser),
59 | subtitle: Text(AppLocalizations.of(context)!.forceExternalBrowserDetails),
60 | onChanged: (bool e) => accessibilityConfig.setForceExternalBrowser(e),
61 | ),
62 | SwitchListTile(
63 | value: accessibilityConfig.debugMode,
64 | title: Text(AppLocalizations.of(context)!.debugMode),
65 | onChanged: (bool e) => accessibilityConfig.setDebugMode(e),
66 | )
67 | ],
68 | ),
69 | ),
70 | ),
71 | ),
72 | );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/scenes/setting/token.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
6 | import 'package:flutter_riverpod/flutter_riverpod.dart';
7 |
8 | // Project imports:
9 | import 'package:vrc_manager/api/data_class.dart';
10 | import 'package:vrc_manager/api/main.dart';
11 | import 'package:vrc_manager/main.dart';
12 | import 'package:vrc_manager/scenes/core/splash.dart';
13 | import 'package:vrc_manager/scenes/setting/logger.dart';
14 | import 'package:vrc_manager/widgets/future/button.dart';
15 |
16 | final tokenControllerProvider = StateProvider.autoDispose((ref) {
17 | return TextEditingController(text: ref.watch(accountConfigProvider).loggedAccount?.cookie ?? "");
18 | });
19 |
20 | class VRChatMobileTokenSetting extends ConsumerWidget {
21 | final bool offline;
22 | const VRChatMobileTokenSetting({super.key, this.offline = true});
23 |
24 | @override
25 | Widget build(BuildContext context, WidgetRef ref) {
26 | TextEditingController tokenController = ref.watch(tokenControllerProvider);
27 |
28 | return Scaffold(
29 | appBar: AppBar(
30 | title: Text(AppLocalizations.of(context)!.token),
31 | ),
32 | body: SafeArea(
33 | child: SingleChildScrollView(
34 | child: Container(
35 | padding: const EdgeInsets.all(32.0),
36 | child: Column(
37 | children: [
38 | TextField(
39 | controller: tokenController,
40 | maxLines: null,
41 | decoration: InputDecoration(labelText: AppLocalizations.of(context)!.cookie),
42 | ),
43 | FutureButton(
44 | type: ButtonType.elevatedButton,
45 | onPressed: () async {
46 | await ref.read(accountConfigProvider).loggedAccount!.setCookie(tokenController.text);
47 | await ref.read(accountConfigProvider).login(ref.read(accountConfigProvider).loggedAccount!);
48 | ScaffoldMessenger.of(context).showSnackBar(
49 | SnackBar(content: Text(AppLocalizations.of(context)!.saved)),
50 | );
51 | },
52 | child: Text(AppLocalizations.of(context)!.save),
53 | ),
54 | FutureButton(
55 | type: ButtonType.elevatedButton,
56 | child: Text(AppLocalizations.of(context)!.login),
57 | onPressed: () async {
58 | await VRChatAPI(
59 | cookie: tokenController.text,
60 | userAgent: ref.watch(accountConfigProvider).userAgent,
61 | logger: logger,
62 | ).user().then((VRChatUserSelfOverload response) {
63 | ScaffoldMessenger.of(context).showSnackBar(
64 | SnackBar(content: Text(AppLocalizations.of(context)!.success)),
65 | );
66 | }).catchError((e, trace) {
67 | logger.w(getMessage(e), error: e, stackTrace: trace);
68 | ScaffoldMessenger.of(context).showSnackBar(
69 | SnackBar(content: Text(AppLocalizations.of(context)!.failed)),
70 | );
71 | });
72 | },
73 | ),
74 | ],
75 | ),
76 | ),
77 | ),
78 | ),
79 | );
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/scenes/sub/json_viewer.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:convert';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 | // Package imports:
7 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
8 | import 'package:flutter_json_viewer/flutter_json_viewer.dart';
9 | import 'package:flutter_riverpod/flutter_riverpod.dart';
10 | // Project imports:
11 | import 'package:vrc_manager/widgets/modal.dart';
12 | import 'package:vrc_manager/widgets/modal/share.dart';
13 |
14 | class VRChatMobileJsonViewer extends ConsumerWidget {
15 | final dynamic content;
16 | const VRChatMobileJsonViewer({super.key, required this.content});
17 |
18 | @override
19 | Widget build(BuildContext context, WidgetRef ref) {
20 | return Scaffold(
21 | appBar: AppBar(
22 | title: Text(AppLocalizations.of(context)!.jsonViewer),
23 | actions: [
24 | IconButton(
25 | icon: const Icon(Icons.share),
26 | onPressed: () {
27 | showModalBottomSheetStatelessWidget(
28 | context: context,
29 | builder: () => SingleChildScrollView(
30 | child: Column(children: [CopyListTileWidget(text: jsonEncode(content))]),
31 | ),
32 | );
33 | },
34 | )
35 | ],
36 | ),
37 | body: Container(
38 | color: Theme.of(context).colorScheme.onPrimary,
39 | child: SafeArea(
40 | child: ListView(
41 | children: [
42 | JsonViewer(content),
43 | ],
44 | ),
45 | ),
46 | ),
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/scenes/sub/world.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 | // Package imports:
4 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 | // Project imports:
7 | import 'package:vrc_manager/api/data_class.dart';
8 | import 'package:vrc_manager/api/main.dart';
9 | import 'package:vrc_manager/main.dart';
10 | import 'package:vrc_manager/scenes/core/splash.dart';
11 | import 'package:vrc_manager/scenes/setting/logger.dart';
12 | import 'package:vrc_manager/widgets/drawer.dart';
13 | import 'package:vrc_manager/widgets/loading.dart';
14 | import 'package:vrc_manager/widgets/modal.dart';
15 | import 'package:vrc_manager/widgets/modal/world.dart';
16 | import 'package:vrc_manager/widgets/scroll.dart';
17 | import 'package:vrc_manager/widgets/world.dart';
18 |
19 | class VRChatMobileWorldData {
20 | VRChatWorld world;
21 |
22 | VRChatMobileWorldData({
23 | required this.world,
24 | });
25 | }
26 |
27 | final vrchatMobileWorldProvider = FutureProvider.family((ref, worldId) async {
28 | VRChatAPI vrchatLoginSession = VRChatAPI(
29 | cookie: ref.watch(accountConfigProvider).loggedAccount?.cookie ?? "",
30 | userAgent: ref.watch(accountConfigProvider).userAgent,
31 | logger: logger,
32 | );
33 |
34 | late VRChatWorld world;
35 | await vrchatLoginSession.worlds(worldId).then((value) => world = value);
36 | return VRChatMobileWorldData(world: world);
37 | });
38 |
39 | class VRChatMobileWorld extends ConsumerWidget {
40 | const VRChatMobileWorld({super.key, required this.worldId});
41 | final String worldId;
42 |
43 | @override
44 | Widget build(BuildContext context, WidgetRef ref) {
45 | AsyncValue data = ref.watch(vrchatMobileWorldProvider(worldId));
46 |
47 | return Scaffold(
48 | appBar: AppBar(
49 | title: Text(AppLocalizations.of(context)!.world),
50 | actions: data.when(
51 | loading: () => null,
52 | error: (e, trace) {
53 | logger.w(getMessage(e), error: e, stackTrace: trace);
54 | return null;
55 | },
56 | data: (data) => [
57 | IconButton(
58 | icon: const Icon(Icons.more_vert),
59 | onPressed: () {
60 | showModalBottomSheetStatelessWidget(
61 | context: context,
62 | builder: () => WorldDetailsModalBottom(world: data.world),
63 | );
64 | },
65 | )
66 | ],
67 | ),
68 | ),
69 | drawer: Navigator.of(context).canPop() ? null : const NormalDrawer(),
70 | body: SafeArea(
71 | child: Consumer(
72 | builder: (context, ref, child) {
73 | return data.when(
74 | loading: () => const Loading(),
75 | error: (e, trace) {
76 | logger.w(getMessage(e), error: e, stackTrace: trace);
77 | return ScrollWidget(
78 | onRefresh: () => ref.refresh((vrchatMobileWorldProvider(worldId).future)),
79 | child: ErrorPage(loggerReport: ref.read(loggerReportProvider)),
80 | );
81 | },
82 | data: (data) => ScrollWidget(
83 | onRefresh: () => ref.refresh((vrchatMobileWorldProvider(worldId).future)),
84 | child: Container(
85 | padding: const EdgeInsets.only(top: 10, right: 30, left: 30),
86 | child: WorldProfile(world: data.world),
87 | ),
88 | ),
89 | );
90 | },
91 | ),
92 | ),
93 | );
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/lib/storage/accessibility.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 |
7 | // Project imports:
8 | import 'package:vrc_manager/assets/storage.dart';
9 | import 'package:vrc_manager/assets/theme/enum.dart';
10 | import 'package:vrc_manager/l10n/code.dart';
11 |
12 | final accessibilityConfigProvider = ChangeNotifierProvider((ref) => AccessibilityConfigNotifier());
13 |
14 | class AccessibilityConfigNotifier extends ChangeNotifier {
15 | LanguageCode languageCode = LanguageCode.en;
16 | ThemeBrightness themeBrightness = ThemeBrightness.light;
17 | ThemeBrightness darkThemeBrightness = ThemeBrightness.dark;
18 | bool forceExternalBrowser = false;
19 | bool debugMode = false;
20 |
21 | AccessibilityConfigNotifier() {
22 | Future.wait([
23 | getStorage("language_code").then((String? value) => languageCode = LanguageCode.values.byName(value ?? languageCode.name)),
24 | getStorage("theme_brightness").then((String? value) => themeBrightness = ThemeBrightness.values.byName(value ?? themeBrightness.name)),
25 | getStorage("dark_theme_brightness").then((String? value) => darkThemeBrightness = ThemeBrightness.values.byName(value ?? darkThemeBrightness.name)),
26 | getStorage("force_external_browser").then((String? value) => forceExternalBrowser = (value == "true")),
27 | getStorage("debug_mode").then((String? value) => debugMode = (value == "true")),
28 | ]).whenComplete(() => notifyListeners());
29 | }
30 |
31 | Future setLanguageCode(LanguageCode value) async {
32 | languageCode = value;
33 | notifyListeners();
34 | return await setStorage("language_code", value.name);
35 | }
36 |
37 | Future setThemeBrightness(ThemeBrightness value) async {
38 | themeBrightness = value;
39 | notifyListeners();
40 | return await setStorage("theme_brightness", themeBrightness.name);
41 | }
42 |
43 | Future setDarkThemeBrightness(ThemeBrightness value) async {
44 | darkThemeBrightness = value;
45 | notifyListeners();
46 | return await setStorage("dark_theme_brightness", darkThemeBrightness.name);
47 | }
48 |
49 | Future setForceExternalBrowser(bool value) async {
50 | forceExternalBrowser = value;
51 | notifyListeners();
52 | return await setStorage("force_external_browser", forceExternalBrowser ? "true" : "false");
53 | }
54 |
55 | Future setDebugMode(bool value) async {
56 | debugMode = value;
57 | notifyListeners();
58 | return await setStorage("debug_mode", debugMode ? "true" : "false");
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/storage/grid_modal.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 |
7 | // Project imports:
8 | import 'package:vrc_manager/assets/storage.dart';
9 | import 'package:vrc_manager/widgets/grid_modal/config.dart';
10 |
11 | final gridConfigProvider = ChangeNotifierProvider.family((ref, id) => GridConfigNotifier(id: id));
12 |
13 | class GridConfigNotifier extends ChangeNotifier {
14 | GridModalConfigType id;
15 | SortMode sortMode = SortMode.normal;
16 | DisplayMode displayMode = DisplayMode.normal;
17 | bool descending = false;
18 | bool joinable = false;
19 | bool worldDetails = false;
20 | bool removeButton = false;
21 |
22 | GridConfigNotifier({required this.id}) {
23 | Future.wait([
24 | getStorage("sort", id: id.name).then((String? value) => sortMode = SortMode.values.byName(value ?? sortMode.name)),
25 | getStorage("display_mode", id: id.name).then((String? value) => displayMode = DisplayMode.values.byName(value ?? displayMode.name)),
26 | getStorage("descending", id: id.name).then((String? value) => descending = (value == "true")),
27 | getStorage("joinable", id: id.name).then((String? value) => joinable = (value == "true")),
28 | getStorage("world_details", id: id.name).then((String? value) => worldDetails = (value == "true")),
29 | getStorage("remove_button", id: id.name).then((String? value) => removeButton = (value == "true")),
30 | ]).whenComplete(() => notifyListeners());
31 | }
32 |
33 | Future setSort(SortMode value) async {
34 | sortMode = value;
35 | notifyListeners();
36 | return await setStorage("sort", value.name, id: id.name);
37 | }
38 |
39 | Future setDisplayMode(DisplayMode value) async {
40 | displayMode = value;
41 | notifyListeners();
42 | return await setStorage("display_mode", displayMode.name, id: id.name);
43 | }
44 |
45 | Future setDescending(bool value) async {
46 | descending = value;
47 | notifyListeners();
48 | return await setStorage("descending", descending ? "true" : "false", id: id.name);
49 | }
50 |
51 | Future setJoinable(bool value) async {
52 | joinable = value;
53 | notifyListeners();
54 | return await setStorage("joinable", joinable ? "true" : "false", id: id.name);
55 | }
56 |
57 | Future setWorldDetails(bool value) async {
58 | worldDetails = value;
59 | notifyListeners();
60 | return await setStorage("world_details", worldDetails ? "true" : "false", id: id.name);
61 | }
62 |
63 | Future setRemoveButton(bool value) async {
64 | removeButton = value;
65 | notifyListeners();
66 | return await setStorage("remove_button", removeButton ? "true" : "false", id: id.name);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/lib/storage/user_policy.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 |
7 | // Project imports:
8 | import 'package:vrc_manager/assets/storage.dart';
9 |
10 | final userPolicyConfigProvider = ChangeNotifierProvider((ref) => UserPolicyConfigNotifier());
11 |
12 | class UserPolicyConfigNotifier extends ChangeNotifier {
13 | bool agree = true;
14 | bool isFirst = true;
15 |
16 | Future init() async {
17 | isFirst = false;
18 | await getStorage("agreed_user_policy").then((String? value) => agree = (value == "true"));
19 | }
20 |
21 | Future setAgree(bool value) async {
22 | agree = value;
23 | notifyListeners();
24 | return await setStorage("agreed_user_policy", agree ? "true" : "false");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/widgets/config_modal/locale.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
6 | import 'package:flutter_riverpod/flutter_riverpod.dart';
7 |
8 | // Project imports:
9 | import 'package:vrc_manager/l10n/code.dart';
10 | import 'package:vrc_manager/storage/accessibility.dart';
11 |
12 | class LocaleModal extends ConsumerWidget {
13 | const LocaleModal({super.key});
14 |
15 | @override
16 | Widget build(BuildContext context, WidgetRef ref) {
17 | final accessibilityConfig = ref.watch(accessibilityConfigProvider);
18 |
19 | return SingleChildScrollView(
20 | child: Column(
21 | children: [
22 | for (LanguageCode value in LanguageCode.values)
23 | ListTile(
24 | title: Text(value.text),
25 | trailing: accessibilityConfig.languageCode == value ? const Icon(Icons.check) : null,
26 | subtitle: Text(
27 | AppLocalizations.of(context)!.translatorDetails(
28 | lookupAppLocalizations(Locale(value.name, "")).contributor,
29 | ),
30 | ),
31 | onTap: () {
32 | accessibilityConfig.setLanguageCode(value);
33 | },
34 | ),
35 | ],
36 | ),
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/widgets/config_modal/theme.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 |
7 | // Project imports:
8 | import 'package:vrc_manager/assets/theme/enum.dart';
9 | import 'package:vrc_manager/storage/accessibility.dart';
10 |
11 | class ThemeBrightnessModal extends ConsumerWidget {
12 | final bool dark;
13 |
14 | const ThemeBrightnessModal({super.key, required this.dark});
15 |
16 | @override
17 | Widget build(BuildContext context, WidgetRef ref) {
18 | AccessibilityConfigNotifier accessibilityConfig = ref.watch(accessibilityConfigProvider);
19 |
20 | return SingleChildScrollView(
21 | child: Column(
22 | children: [
23 | for (ThemeBrightness value in ThemeBrightness.values)
24 | ListTile(
25 | title: Text(value.toLocalization(context)),
26 | trailing: (dark ? accessibilityConfig.darkThemeBrightness : accessibilityConfig.themeBrightness) == value ? const Icon(Icons.check) : null,
27 | onTap: () => dark ? accessibilityConfig.setDarkThemeBrightness(value) : accessibilityConfig.setThemeBrightness(value),
28 | ),
29 | ],
30 | ),
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/widgets/future/button.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/scheduler.dart';
4 |
5 | enum ButtonType {
6 | textButton,
7 | outlinedButton,
8 | elevatedButton;
9 | }
10 |
11 | class FutureButton extends StatefulWidget {
12 | final Widget child;
13 | final Future Function() onPressed;
14 | final ButtonType type;
15 | const FutureButton({super.key, required this.child, required this.onPressed, this.type = ButtonType.textButton});
16 |
17 | @override
18 | FutureButtonState createState() => FutureButtonState();
19 | }
20 |
21 | class FutureButtonState extends State {
22 | late bool state;
23 | late Size size;
24 | late GlobalKey key;
25 |
26 | @override
27 | void initState() {
28 | state = false;
29 | key = GlobalKey();
30 | super.initState();
31 | }
32 |
33 | Future onPressed() async {
34 | try {
35 | setState(() => state = true);
36 | await widget.onPressed();
37 | } finally {
38 | setState(() => state = false);
39 | }
40 | }
41 |
42 | @override
43 | Widget build(BuildContext context) {
44 | if (state) {
45 | return SizedBox(
46 | width: size.width,
47 | height: size.height,
48 | child: Padding(
49 | padding: EdgeInsets.symmetric(vertical: (size.height - 20) / 2, horizontal: (size.width - 20) / 2),
50 | child: const CircularProgressIndicator(),
51 | ),
52 | );
53 | }
54 |
55 | SchedulerBinding.instance.addPostFrameCallback((_) {
56 | size = key.currentContext!.size!;
57 | });
58 |
59 | switch (widget.type) {
60 | case ButtonType.textButton:
61 | return TextButton(
62 | key: key,
63 | onPressed: onPressed,
64 | child: widget.child,
65 | );
66 | case ButtonType.outlinedButton:
67 | return OutlinedButton(
68 | key: key,
69 | onPressed: onPressed,
70 | child: widget.child,
71 | );
72 | case ButtonType.elevatedButton:
73 | return ElevatedButton(
74 | key: key,
75 | onPressed: onPressed,
76 | child: widget.child,
77 | );
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/lib/widgets/future/tile.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | class FutureTile extends StatefulWidget {
5 | final Widget? title;
6 | final Widget? subtitle;
7 | final Widget? leading;
8 | final Widget? trailing;
9 |
10 | final Future Function() onTap;
11 | const FutureTile({super.key, this.title, this.subtitle, this.leading, this.trailing, required this.onTap});
12 |
13 | @override
14 | FutureTileState createState() => FutureTileState();
15 | }
16 |
17 | class FutureTileState extends State {
18 | late bool state;
19 | late GlobalKey key;
20 |
21 | @override
22 | void initState() {
23 | state = false;
24 | key = GlobalKey();
25 | super.initState();
26 | }
27 |
28 | Future onTap() async {
29 | try {
30 | setState(() => state = true);
31 | await widget.onTap();
32 | } finally {
33 | setState(() => state = false);
34 | }
35 | }
36 |
37 | @override
38 | Widget build(BuildContext context) {
39 | return ListTile(
40 | key: key,
41 | onTap: onTap,
42 | title: widget.title,
43 | subtitle: widget.subtitle,
44 | leading: widget.leading,
45 | trailing: state
46 | ? const Padding(
47 | padding: EdgeInsets.only(right: 2, top: 2),
48 | child: SizedBox(width: 20, height: 20, child: CircularProgressIndicator()),
49 | )
50 | : widget.trailing,
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/widgets/grid_view/extraction/consumer.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/widgets.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 |
7 | // Project imports:
8 | import 'package:vrc_manager/storage/grid_modal.dart';
9 | import 'package:vrc_manager/widgets/grid_modal/config.dart';
10 | import 'package:vrc_manager/widgets/grid_view/template/template.dart';
11 |
12 | abstract class ConsumerGridWidget extends ConsumerWidget {
13 | final GridModalConfigType id;
14 | const ConsumerGridWidget({super.key, required this.id});
15 |
16 | List normal(BuildContext context, WidgetRef ref, GridConfigNotifier config, ConsumerGridStyle style);
17 |
18 | List simple(BuildContext context, WidgetRef ref, GridConfigNotifier config, ConsumerGridStyle style);
19 |
20 | List textOnly(BuildContext context, WidgetRef ref, GridConfigNotifier config, ConsumerGridStyle style);
21 |
22 | @override
23 | Widget build(BuildContext context, WidgetRef ref) {
24 | GridConfigNotifier config = ref.watch(gridConfigProvider(id));
25 |
26 | switch (config.displayMode) {
27 | case DisplayMode.normal:
28 | final style = ConsumerGridStyle(
29 | title: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
30 | details: const TextStyle(fontSize: 15),
31 | );
32 | return RenderGrid(
33 | width: 600,
34 | height: config.worldDetails ? 235 : 130,
35 | children: normal(context, ref, config, style),
36 | );
37 | case DisplayMode.simple:
38 | final style = ConsumerGridStyle(
39 | title: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
40 | details: const TextStyle(fontSize: 10),
41 | );
42 | return RenderGrid(
43 | width: 320,
44 | height: config.worldDetails ? 119 : 64,
45 | children: simple(context, ref, config, style),
46 | );
47 | case DisplayMode.textOnly:
48 | final style = ConsumerGridStyle(
49 | title: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
50 | details: const TextStyle(fontSize: 10),
51 | );
52 | return RenderGrid(
53 | width: 200,
54 | height: config.worldDetails ? 27 : 20,
55 | children: textOnly(context, ref, config, style),
56 | );
57 | }
58 | }
59 | }
60 |
61 | class ConsumerGridStyle {
62 | final TextStyle title;
63 | final TextStyle details;
64 | ConsumerGridStyle({required this.title, required this.details});
65 | }
66 |
--------------------------------------------------------------------------------
/lib/widgets/loading.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 |
7 | class Loading extends ConsumerWidget {
8 | const Loading({super.key});
9 |
10 | @override
11 | Widget build(BuildContext context, WidgetRef ref) {
12 | return Container(
13 | alignment: Alignment.topCenter,
14 | child: const Padding(
15 | padding: EdgeInsets.only(top: 40),
16 | child: CircularProgressIndicator(),
17 | ),
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/widgets/modal.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 |
7 | Future showModalBottomSheetConsumer({
8 | required BuildContext context,
9 | required ConsumerBuilder builder,
10 | }) {
11 | assert(debugCheckHasMediaQuery(context));
12 | assert(debugCheckHasMaterialLocalizations(context));
13 |
14 | return showModalBottomSheet(
15 | context: context,
16 | shape: const RoundedRectangleBorder(
17 | borderRadius: BorderRadius.vertical(top: Radius.circular(15)),
18 | ),
19 | builder: (BuildContext context) {
20 | return Consumer(
21 | builder: builder,
22 | );
23 | },
24 | );
25 | }
26 |
27 | Future showModalBottomSheetStatelessWidget({
28 | required BuildContext context,
29 | required Widget Function() builder,
30 | }) {
31 | assert(debugCheckHasMediaQuery(context));
32 | assert(debugCheckHasMaterialLocalizations(context));
33 |
34 | return showModalBottomSheet(
35 | context: context,
36 | shape: const RoundedRectangleBorder(
37 | borderRadius: BorderRadius.vertical(top: Radius.circular(15)),
38 | ),
39 | builder: (BuildContext context) => builder(),
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/lib/widgets/region.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | // Package imports:
3 | import 'package:cached_network_image/cached_network_image.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 | // Project imports:
7 | import 'package:vrc_manager/api/assets/region.dart';
8 | import 'package:vrc_manager/scenes/core/splash.dart';
9 |
10 | class RegionWidget extends ConsumerWidget {
11 | final VRChatRegion region;
12 | final double size;
13 | const RegionWidget({required this.region, this.size = 15, super.key});
14 |
15 | @override
16 | Widget build(BuildContext context, WidgetRef ref) {
17 | return SizedBox(
18 | width: size,
19 | height: size,
20 | child: CachedNetworkImage(
21 | imageUrl: region.toUri().toString(),
22 | fit: BoxFit.fitWidth,
23 | progressIndicatorBuilder: (context, url, downloadProgress) => const CircularProgressIndicator(),
24 | errorWidget: (context, url, error) => const Icon(Icons.error),
25 | httpHeaders: {
26 | "user-agent": ref.watch(accountConfigProvider).userAgent,
27 | },
28 | ),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/widgets/scroll.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:flutter_riverpod/flutter_riverpod.dart';
6 |
7 | class ScrollWidget extends ConsumerWidget {
8 | final RefreshCallback onRefresh;
9 | final ScrollNotificationPredicate notificationPredicate;
10 | final Widget child;
11 |
12 | const ScrollWidget({
13 | super.key,
14 | required this.onRefresh,
15 | required this.child,
16 | this.notificationPredicate = defaultScrollNotificationPredicate,
17 | });
18 |
19 | @override
20 | Widget build(BuildContext context, WidgetRef ref) {
21 | return RefreshIndicator(
22 | onRefresh: onRefresh,
23 | notificationPredicate: notificationPredicate,
24 | child: SizedBox(
25 | height: double.infinity,
26 | width: double.infinity,
27 | child: SingleChildScrollView(
28 | keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
29 | physics: const AlwaysScrollableScrollPhysics(),
30 | child: child,
31 | ),
32 | ),
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/widgets/share.dart:
--------------------------------------------------------------------------------
1 | // Dart imports:
2 | import 'dart:io';
3 |
4 | // Flutter imports:
5 | import 'package:flutter/material.dart';
6 | import 'package:flutter/services.dart';
7 |
8 | // Package imports:
9 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
10 | import 'package:fluttertoast/fluttertoast.dart';
11 | import 'package:url_launcher/url_launcher.dart';
12 |
13 | // Project imports:
14 | import 'package:vrc_manager/api/assets/assets.dart';
15 | import 'package:vrc_manager/scenes/web/web_view.dart';
16 |
17 | Future openInBrowser({required Uri url, required bool forceExternal}) async {
18 | if (Platform.isAndroid || Platform.isIOS) {
19 | if (!forceExternal || url.host == VRChatAssets.vrchat.host) {
20 | return VRChatMobileWebView(initUrl: url);
21 | } else {
22 | if (await canLaunchUrl(url)) {
23 | await launchUrl(url, mode: LaunchMode.externalApplication);
24 | }
25 | }
26 | } else {
27 | if (await canLaunchUrl(url)) {
28 | await launchUrl(url);
29 | }
30 | }
31 | return null;
32 | }
33 |
34 | Future copyToClipboard(BuildContext context, String text) async {
35 | final ClipboardData data = ClipboardData(text: text);
36 | await Clipboard.setData(data);
37 | if (Platform.isAndroid || Platform.isIOS) {
38 | Fluttertoast.showToast(msg: AppLocalizations.of(context)!.copied);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/widgets/status.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 | // Package imports:
4 | import 'package:flutter_riverpod/flutter_riverpod.dart';
5 | // Project imports:
6 | import 'package:vrc_manager/api/assets/status.dart';
7 |
8 | // Project imports:
9 | class StatusWidget extends ConsumerWidget {
10 | final VRChatStatusData status;
11 | final double diameter;
12 | const StatusWidget({required this.status, this.diameter = 20, super.key});
13 |
14 | @override
15 | Widget build(BuildContext context, WidgetRef ref) {
16 | return Container(
17 | width: diameter,
18 | height: diameter,
19 | decoration: BoxDecoration(
20 | shape: BoxShape.circle,
21 | color: status.toColor(),
22 | ),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/widgets/world.dart:
--------------------------------------------------------------------------------
1 | // Flutter imports:
2 | import 'package:flutter/material.dart';
3 |
4 | // Package imports:
5 | import 'package:cached_network_image/cached_network_image.dart';
6 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
7 | import 'package:flutter_riverpod/flutter_riverpod.dart';
8 |
9 | // Project imports:
10 | import 'package:vrc_manager/api/data_class.dart';
11 | import 'package:vrc_manager/assets/date.dart';
12 | import 'package:vrc_manager/scenes/core/splash.dart';
13 |
14 | class OnTheWebsite extends ConsumerWidget {
15 | final bool half;
16 | const OnTheWebsite({super.key, this.half = false});
17 |
18 | @override
19 | Widget build(BuildContext context, WidgetRef ref) {
20 | return Container(
21 | alignment: Alignment.center,
22 | height: half ? 50 : 100,
23 | child: Text(AppLocalizations.of(context)!.onTheWebsite, style: TextStyle(fontSize: half ? 10 : 15)),
24 | );
25 | }
26 | }
27 |
28 | class WorldProfile extends ConsumerWidget {
29 | final VRChatWorld world;
30 | const WorldProfile({super.key, required this.world});
31 |
32 | @override
33 | Widget build(BuildContext context, WidgetRef ref) {
34 | return Column(
35 | children: [
36 | SizedBox(
37 | height: 250,
38 | child: CachedNetworkImage(
39 | imageUrl: world.imageUrl,
40 | fit: BoxFit.fitWidth,
41 | progressIndicatorBuilder: (context, url, downloadProgress) => const SizedBox(
42 | width: 250.0,
43 | child: Padding(
44 | padding: EdgeInsets.all(30),
45 | child: CircularProgressIndicator(
46 | strokeWidth: 10,
47 | ),
48 | ),
49 | ),
50 | errorWidget: (context, url, error) => const SizedBox(
51 | width: 250.0,
52 | child: Icon(Icons.error),
53 | ),
54 | httpHeaders: {
55 | "user-agent": ref.watch(accountConfigProvider).userAgent,
56 | },
57 | ),
58 | ),
59 | Text(world.name,
60 | style: const TextStyle(
61 | fontWeight: FontWeight.bold,
62 | fontSize: 20,
63 | )),
64 | ConstrainedBox(
65 | constraints: const BoxConstraints(maxHeight: 200),
66 | child: SingleChildScrollView(child: Text(world.description ?? "")),
67 | ),
68 | Text(
69 | AppLocalizations.of(context)!.occupants(world.occupants),
70 | ),
71 | Text(
72 | AppLocalizations.of(context)!.privateOccupants(world.privateOccupants),
73 | ),
74 | Text(
75 | AppLocalizations.of(context)!.favorites(world.favorites),
76 | ),
77 | Text(
78 | AppLocalizations.of(context)!.createdAt(
79 | generalDateDifference(context, world.createdAt),
80 | ),
81 | ),
82 | Text(
83 | AppLocalizations.of(context)!.updatedAt(
84 | generalDateDifference(context, world.updatedAt),
85 | ),
86 | ),
87 | ],
88 | );
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: vrc_manager
2 | description: VRCManager
3 |
4 | publish_to: "none"
5 | version: 5.1.0+25
6 |
7 | environment:
8 | sdk: ">=2.17.0 <4.0.0"
9 | dependencies:
10 | cached_network_image: ^3.2.1
11 | cupertino_icons: ^1.0.4
12 | device_info_plus: ^10.1.2
13 | domain_verification_manager: ^1.0.0
14 | flutter:
15 | sdk: flutter
16 | flutter_inappwebview: ^6.1.0+1
17 | flutter_json_viewer: ^1.0.1
18 | flutter_localizations:
19 | sdk: flutter
20 | flutter_riverpod: ^2.0.2
21 | flutter_secure_storage: ^9.2.2
22 | flutter_svg: ^2.0.6
23 | fluttertoast: ^8.0.9
24 | http: ^1.1.0
25 | intl: ^0.19.0
26 | logger: ^2.0.1
27 | package_info_plus: ^8.0.2
28 | flutter_sharing_intent: ^1.1.1
29 | share_plus: ^10.0.2
30 | shared_preferences: ^2.0.15
31 | url_launcher: ^6.1.2
32 | webview_flutter: <4.0.0
33 |
34 | dev_dependencies:
35 | flutter_launcher_icons: ^0.14.0
36 | flutter_lints: ^4.0.0
37 | flutter_test:
38 | sdk: flutter
39 | import_sorter: ^4.6.0
40 |
41 | flutter:
42 | assets:
43 | - assets/svg/
44 | generate: true
45 | uses-material-design: true
46 |
47 | flutter_icons:
48 | android: true
49 | ios: true
50 | remove_alpha_ios: true
51 | image_path: "assets/img/icon.png"
52 |
--------------------------------------------------------------------------------
/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/windows/build.ps1:
--------------------------------------------------------------------------------
1 | flutter build windows
2 | Start-Process "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "Z:\Project\flutter\vrc_manager\windows\setup.iss"
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | void RegisterPlugins(flutter::PluginRegistry* registry) {
15 | FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(
16 | registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
17 | FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
18 | registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
19 | SharePlusWindowsPluginCApiRegisterWithRegistrar(
20 | registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
21 | UrlLauncherWindowsRegisterWithRegistrar(
22 | registry->GetRegistrarForPlugin("UrlLauncherWindows"));
23 | }
24 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | flutter_inappwebview_windows
7 | flutter_secure_storage_windows
8 | share_plus
9 | url_launcher_windows
10 | )
11 |
12 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
13 | )
14 |
15 | set(PLUGIN_BUNDLED_LIBRARIES)
16 |
17 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
18 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
19 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
21 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
22 | endforeach(plugin)
23 |
24 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
25 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
26 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
27 | endforeach(ffi_plugin)
28 |
--------------------------------------------------------------------------------
/windows/runner/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | project(runner LANGUAGES CXX)
3 |
4 | # Define the application target. To change its name, change BINARY_NAME in the
5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
6 | # work.
7 | #
8 | # Any new source files that you add to the application should be added here.
9 | add_executable(${BINARY_NAME} WIN32
10 | "flutter_window.cpp"
11 | "main.cpp"
12 | "utils.cpp"
13 | "win32_window.cpp"
14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
15 | "Runner.rc"
16 | "runner.exe.manifest"
17 | )
18 |
19 | # Apply the standard set of build settings. This can be removed for applications
20 | # that need different build settings.
21 | apply_standard_settings(${BINARY_NAME})
22 |
23 | # Add preprocessor definitions for the build version.
24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
29 |
30 | # Disable Windows macros that collide with C++ standard library functions.
31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
32 |
33 | # Add dependency libraries and include directories. Add any application-specific
34 | # dependencies here.
35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
38 |
39 | # Run the Flutter tool portions of the build. This must not be removed.
40 | add_dependencies(${BINARY_NAME} flutter_assemble)
41 |
--------------------------------------------------------------------------------
/windows/runner/Runner.rc:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #pragma code_page(65001)
4 | #include "resource.h"
5 |
6 | #define APSTUDIO_READONLY_SYMBOLS
7 | /////////////////////////////////////////////////////////////////////////////
8 | //
9 | // Generated from the TEXTINCLUDE 2 resource.
10 | //
11 | #include "winres.h"
12 |
13 | /////////////////////////////////////////////////////////////////////////////
14 | #undef APSTUDIO_READONLY_SYMBOLS
15 |
16 | /////////////////////////////////////////////////////////////////////////////
17 | // English (United States) resources
18 |
19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
21 |
22 | #ifdef APSTUDIO_INVOKED
23 | /////////////////////////////////////////////////////////////////////////////
24 | //
25 | // TEXTINCLUDE
26 | //
27 |
28 | 1 TEXTINCLUDE
29 | BEGIN
30 | "resource.h\0"
31 | END
32 |
33 | 2 TEXTINCLUDE
34 | BEGIN
35 | "#include ""winres.h""\r\n"
36 | "\0"
37 | END
38 |
39 | 3 TEXTINCLUDE
40 | BEGIN
41 | "\r\n"
42 | "\0"
43 | END
44 |
45 | #endif // APSTUDIO_INVOKED
46 |
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 | //
50 | // Icon
51 | //
52 |
53 | // Icon with lowest ID value placed first to ensure application icon
54 | // remains consistent on all systems.
55 | IDI_APP_ICON ICON "resources\\app_icon.ico"
56 |
57 |
58 | /////////////////////////////////////////////////////////////////////////////
59 | //
60 | // Version
61 | //
62 |
63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
65 | #else
66 | #define VERSION_AS_NUMBER 1,0,0,0
67 | #endif
68 |
69 | #if defined(FLUTTER_VERSION)
70 | #define VERSION_AS_STRING FLUTTER_VERSION
71 | #else
72 | #define VERSION_AS_STRING "1.0.0"
73 | #endif
74 |
75 | VS_VERSION_INFO VERSIONINFO
76 | FILEVERSION VERSION_AS_NUMBER
77 | PRODUCTVERSION VERSION_AS_NUMBER
78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
79 | #ifdef _DEBUG
80 | FILEFLAGS VS_FF_DEBUG
81 | #else
82 | FILEFLAGS 0x0L
83 | #endif
84 | FILEOS VOS__WINDOWS32
85 | FILETYPE VFT_APP
86 | FILESUBTYPE 0x0L
87 | BEGIN
88 | BLOCK "StringFileInfo"
89 | BEGIN
90 | BLOCK "040904e4"
91 | BEGIN
92 | VALUE "CompanyName", "com.yuki0311" "\0"
93 | VALUE "FileDescription", "vrc_manager" "\0"
94 | VALUE "FileVersion", VERSION_AS_STRING "\0"
95 | VALUE "InternalName", "vrc_manager" "\0"
96 | VALUE "LegalCopyright", "Copyright (C) 2024 com.yuki0311. All rights reserved." "\0"
97 | VALUE "OriginalFilename", "vrc_manager.exe" "\0"
98 | VALUE "ProductName", "vrc_manager" "\0"
99 | VALUE "ProductVersion", VERSION_AS_STRING "\0"
100 | END
101 | END
102 | BLOCK "VarFileInfo"
103 | BEGIN
104 | VALUE "Translation", 0x409, 1252
105 | END
106 | END
107 |
108 | #endif // English (United States) resources
109 | /////////////////////////////////////////////////////////////////////////////
110 |
111 |
112 |
113 | #ifndef APSTUDIO_INVOKED
114 | /////////////////////////////////////////////////////////////////////////////
115 | //
116 | // Generated from the TEXTINCLUDE 3 resource.
117 | //
118 |
119 |
120 | /////////////////////////////////////////////////////////////////////////////
121 | #endif // not APSTUDIO_INVOKED
122 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.cpp:
--------------------------------------------------------------------------------
1 | #include "flutter_window.h"
2 |
3 | #include
4 |
5 | #include "flutter/generated_plugin_registrant.h"
6 |
7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project)
8 | : project_(project) {}
9 |
10 | FlutterWindow::~FlutterWindow() {}
11 |
12 | bool FlutterWindow::OnCreate() {
13 | if (!Win32Window::OnCreate()) {
14 | return false;
15 | }
16 |
17 | RECT frame = GetClientArea();
18 |
19 | // The size here must match the window dimensions to avoid unnecessary surface
20 | // creation / destruction in the startup path.
21 | flutter_controller_ = std::make_unique(
22 | frame.right - frame.left, frame.bottom - frame.top, project_);
23 | // Ensure that basic setup of the controller was successful.
24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) {
25 | return false;
26 | }
27 | RegisterPlugins(flutter_controller_->engine());
28 | SetChildContent(flutter_controller_->view()->GetNativeWindow());
29 |
30 | flutter_controller_->engine()->SetNextFrameCallback([&]() {
31 | this->Show();
32 | });
33 |
34 | // Flutter can complete the first frame before the "show window" callback is
35 | // registered. The following call ensures a frame is pending to ensure the
36 | // window is shown. It is a no-op if the first frame hasn't completed yet.
37 | flutter_controller_->ForceRedraw();
38 |
39 | return true;
40 | }
41 |
42 | void FlutterWindow::OnDestroy() {
43 | if (flutter_controller_) {
44 | flutter_controller_ = nullptr;
45 | }
46 |
47 | Win32Window::OnDestroy();
48 | }
49 |
50 | LRESULT
51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
52 | WPARAM const wparam,
53 | LPARAM const lparam) noexcept {
54 | // Give Flutter, including plugins, an opportunity to handle window messages.
55 | if (flutter_controller_) {
56 | std::optional result =
57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
58 | lparam);
59 | if (result) {
60 | return *result;
61 | }
62 | }
63 |
64 | switch (message) {
65 | case WM_FONTCHANGE:
66 | flutter_controller_->engine()->ReloadSystemFonts();
67 | break;
68 | }
69 |
70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
71 | }
72 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "win32_window.h"
10 |
11 | // A window that does nothing but host a Flutter view.
12 | class FlutterWindow : public Win32Window {
13 | public:
14 | // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 | explicit FlutterWindow(const flutter::DartProject& project);
16 | virtual ~FlutterWindow();
17 |
18 | protected:
19 | // Win32Window:
20 | bool OnCreate() override;
21 | void OnDestroy() override;
22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 | LPARAM const lparam) noexcept override;
24 |
25 | private:
26 | // The project to run.
27 | flutter::DartProject project_;
28 |
29 | // The Flutter instance hosted by this window.
30 | std::unique_ptr flutter_controller_;
31 | };
32 |
33 | #endif // RUNNER_FLUTTER_WINDOW_H_
34 |
--------------------------------------------------------------------------------
/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "utils.h"
7 |
8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 | _In_ wchar_t *command_line, _In_ int show_command) {
10 | // Attach to console when present (e.g., 'flutter run') or create a
11 | // new console when running with a debugger.
12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 | CreateAndAttachConsole();
14 | }
15 |
16 | // Initialize COM, so that it is available for use in the library and/or
17 | // plugins.
18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 |
20 | flutter::DartProject project(L"data");
21 |
22 | std::vector command_line_arguments =
23 | GetCommandLineArguments();
24 |
25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 |
27 | FlutterWindow window(project);
28 | Win32Window::Point origin(10, 10);
29 | Win32Window::Size size(1280, 720);
30 | if (!window.Create(L"vrc_manager", origin, size)) {
31 | return EXIT_FAILURE;
32 | }
33 | window.SetQuitOnClose(true);
34 |
35 | ::MSG msg;
36 | while (::GetMessage(&msg, nullptr, 0, 0)) {
37 | ::TranslateMessage(&msg);
38 | ::DispatchMessage(&msg);
39 | }
40 |
41 | ::CoUninitialize();
42 | return EXIT_SUCCESS;
43 | }
44 |
--------------------------------------------------------------------------------
/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fa0311/vrc_manager/8f0a11a84c646804c2a68a1b6d0754d617f2b00f/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/windows/runner/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | void CreateAndAttachConsole() {
11 | if (::AllocConsole()) {
12 | FILE *unused;
13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 | _dup2(_fileno(stdout), 1);
15 | }
16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 | _dup2(_fileno(stdout), 2);
18 | }
19 | std::ios::sync_with_stdio();
20 | FlutterDesktopResyncOutputStreams();
21 | }
22 | }
23 |
24 | std::vector GetCommandLineArguments() {
25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 | int argc;
27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 | if (argv == nullptr) {
29 | return std::vector();
30 | }
31 |
32 | std::vector command_line_arguments;
33 |
34 | // Skip the first argument as it's the binary name.
35 | for (int i = 1; i < argc; i++) {
36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 | }
38 |
39 | ::LocalFree(argv);
40 |
41 | return command_line_arguments;
42 | }
43 |
44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 | if (utf16_string == nullptr) {
46 | return std::string();
47 | }
48 | unsigned int target_length = ::WideCharToMultiByte(
49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 | -1, nullptr, 0, nullptr, nullptr)
51 | -1; // remove the trailing null character
52 | int input_length = (int)wcslen(utf16_string);
53 | std::string utf8_string;
54 | if (target_length == 0 || target_length > utf8_string.max_size()) {
55 | return utf8_string;
56 | }
57 | utf8_string.resize(target_length);
58 | int converted_length = ::WideCharToMultiByte(
59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
60 | input_length, utf8_string.data(), target_length, nullptr, nullptr);
61 | if (converted_length == 0) {
62 | return std::string();
63 | }
64 | return utf8_string;
65 | }
66 |
--------------------------------------------------------------------------------
/windows/runner/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_UTILS_H_
2 | #define RUNNER_UTILS_H_
3 |
4 | #include
5 | #include
6 |
7 | // Creates a console for the process, and redirects stdout and stderr to
8 | // it for both the runner and the Flutter library.
9 | void CreateAndAttachConsole();
10 |
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 |
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 |
19 | #endif // RUNNER_UTILS_H_
20 |
--------------------------------------------------------------------------------
/windows/setup.iss:
--------------------------------------------------------------------------------
1 | ; Script generated by the Inno Setup Script Wizard.
2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
3 |
4 | #define MyAppName "VRCManager"
5 | #define MyAppVersion "5.0.3"
6 | #define MyAppPublisher "yuki"
7 | #define MyAppURL "https://yuki0311.com/"
8 | #define MyAppExeName "vrc_manager.exe"
9 | #define MyAppAssocName MyAppName + " File"
10 | #define MyAppAssocExt ".myp"
11 | #define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt
12 |
13 | [Setup]
14 | ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
15 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
16 | AppId={{1B55B29A-0DD9-4CEB-AEC3-B40F2CD877B9}
17 | AppName={#MyAppName}
18 | AppVersion={#MyAppVersion}
19 | ;AppVerName={#MyAppName} {#MyAppVersion}
20 | AppPublisher={#MyAppPublisher}
21 | AppPublisherURL={#MyAppURL}
22 | AppSupportURL={#MyAppURL}
23 | AppUpdatesURL={#MyAppURL}
24 | DefaultDirName={autopf}\{#MyAppName}
25 | ChangesAssociations=yes
26 | DisableProgramGroupPage=yes
27 | LicenseFile=Z:\Project\flutter\vrc_manager\LICENSE
28 | ; Uncomment the following line to run in non administrative install mode (install for current user only.)
29 | ;PrivilegesRequired=lowest
30 | OutputDir=Z:\Project\flutter\vrc_manager\build\windows
31 | OutputBaseFilename=VRChatMC-Setup
32 | SetupIconFile=Z:\Project\flutter\vrc_manager\windows\runner\resources\app_icon.ico
33 | Compression=lzma
34 | SolidCompression=yes
35 | WizardStyle=modern
36 |
37 | [Languages]
38 | Name: "english"; MessagesFile: "compiler:Default.isl"
39 | Name: "japanese"; MessagesFile: "compiler:Languages\Japanese.isl"
40 |
41 | [Tasks]
42 | Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
43 |
44 | [Files]
45 | Source: "Z:\Project\flutter\vrc_manager\build\windows\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
46 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
47 |
48 | [Registry]
49 | Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue
50 | Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey
51 | Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
52 | Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
53 | Root: HKA; Subkey: "Software\Classes\Applications\{#MyAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".myp"; ValueData: ""
54 |
55 | [Icons]
56 | Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
57 | Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
58 |
59 | [Run]
60 | Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
61 |
62 |
--------------------------------------------------------------------------------