diff --git a/.flutter-plugins b/.flutter-plugins index a1b8752..ba6e378 100644 --- a/.flutter-plugins +++ b/.flutter-plugins @@ -1,11 +1,8 @@ # This is a generated file; do not edit or check into version control. -file_selector=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\file_selector-0.8.2\\ -file_selector_linux=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\file_selector_linux-0.0.2+1\\ -file_selector_macos=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\file_selector_macos-0.0.4+1\\ -file_selector_web=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\file_selector_web-0.8.1+2\\ -file_selector_windows=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\file_selector_windows-0.0.2+1\\ -url_launcher=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\url_launcher-6.0.9\\ -url_launcher_linux=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\url_launcher_linux-2.0.1\\ -url_launcher_macos=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\url_launcher_macos-2.0.1\\ -url_launcher_web=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\url_launcher_web-2.0.4\\ -url_launcher_windows=C:\\Users\\siongsng\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dartlang.org\\url_launcher_windows-2.0.2\\ +url_launcher=/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.20/ +url_launcher_android=/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/ +url_launcher_ios=/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/ +url_launcher_linux=/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/ +url_launcher_macos=/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/ +url_launcher_web=/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/ +url_launcher_windows=/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/ diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index a2fced1..5d61a8b 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"url_launcher","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\url_launcher-6.0.9\\\\","dependencies":[]}],"android":[{"name":"url_launcher","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\url_launcher-6.0.9\\\\","dependencies":[]}],"macos":[{"name":"file_selector_macos","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\file_selector_macos-0.0.4+1\\\\","dependencies":[]},{"name":"url_launcher_macos","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\url_launcher_macos-2.0.1\\\\","dependencies":[]}],"linux":[{"name":"file_selector_linux","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\file_selector_linux-0.0.2+1\\\\","dependencies":[]},{"name":"url_launcher_linux","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\url_launcher_linux-2.0.1\\\\","dependencies":[]}],"windows":[{"name":"file_selector_windows","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\file_selector_windows-0.0.2+1\\\\","dependencies":[]},{"name":"url_launcher_windows","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\url_launcher_windows-2.0.2\\\\","dependencies":[]}],"web":[{"name":"file_selector_web","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\file_selector_web-0.8.1+2\\\\","dependencies":[]},{"name":"url_launcher_web","path":"C:\\\\Users\\\\siongsng\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\url_launcher_web-2.0.4\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"file_selector","dependencies":["file_selector_web"]},{"name":"file_selector_linux","dependencies":[]},{"name":"file_selector_macos","dependencies":[]},{"name":"file_selector_web","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-10-09 21:44:13.736801","version":"2.6.0-12.0.pre.287"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"url_launcher_ios","path":"/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_ios-6.0.15/","native_build":true,"dependencies":[]}],"android":[{"name":"url_launcher_android","path":"/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_android-6.0.15/","native_build":true,"dependencies":[]}],"macos":[{"name":"url_launcher_macos","path":"/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-3.0.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"url_launcher_linux","path":"/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-3.0.0/","native_build":true,"dependencies":[]}],"windows":[{"name":"url_launcher_windows","path":"/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-3.0.0/","native_build":true,"dependencies":[]}],"web":[{"name":"url_launcher_web","path":"/home/siongsng/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-2.0.9/","dependencies":[]}]},"dependencyGraph":[{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-03-27 23:12:13.108926","version":"2.12.0-4.1.pre"} \ No newline at end of file diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index d057b36..ce6340c 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -12,9 +12,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: subosito/flutter-action@v1 + - name: Cache flutter + uses: actions/cache@v2 with: - channel: master - - uses: bluefireteam/flutter-gh-pages@v7 + path: /opt/hostedtoolcache/flutter + key: ${{ runner.os }}-flutter-2.12.0-4.1.pre + - uses: subosito/flutter-action@master with: - webRenderer: html + channel: beta + flutter-version: 2.12.0-4.1.pre + - uses: bluefireteam/flutter-gh-pages@v8 diff --git a/.vscode/launch.json b/.vscode/launch.json index 1a91629..53713b8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,18 +5,16 @@ "version": "0.2.0", "configurations": [ { - "name": "rpmtranslator", + "name": "RPMTranslator", "request": "launch", "type": "dart", "args": [ - "--web-port=54091", - "--web-renderer", - "html" + "--web-port=54091" ], "externalConsole": true, }, { - "name": "rpmtranslator (profile mode)", + "name": "RPMTranslator (profile mode)", "request": "launch", "type": "dart", "flutterMode": "profile", diff --git a/fonts/NotoSansCJKtc-Regular.otf b/assets/fonts/NotoSansCJKtc-Regular.otf similarity index 100% rename from fonts/NotoSansCJKtc-Regular.otf rename to assets/fonts/NotoSansCJKtc-Regular.otf diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..df68ffb Binary files /dev/null and b/assets/images/logo.png differ diff --git a/assets/images/logo.svg b/assets/images/logo.svg new file mode 100644 index 0000000..c85c5bb --- /dev/null +++ b/assets/images/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/API/APIs.dart b/lib/API/APIs.dart deleted file mode 100644 index 289e936..0000000 --- a/lib/API/APIs.dart +++ /dev/null @@ -1,9 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, prefer_const_literals_to_create_immutables - -String HomePageUrl = "https://www.rpmtw.com"; -String RPMTWProgressAPI = - "https://raw.githubusercontent.com/RPMTW/RPMTW-website-data/main/data/progress.json"; -String RPMTWContributionAPI = "https://raw.githubusercontent.com/RPMTW/RPMTW-website-data/main/data/opt.json"; -String CrowdinBaseAPI = "https://api.crowdin.com/api/v2"; -String RPMCrowdinBaseAPI = "https://rear-end.a102009102009.repl.co/crowdin/api"; -String CurseForgeAPI = "https://rear-end.a102009102009.repl.co/curseForge/api"; diff --git a/lib/API/CrowdinAPI.dart b/lib/API/CrowdinAPI.dart deleted file mode 100644 index b4c2e51..0000000 --- a/lib/API/CrowdinAPI.dart +++ /dev/null @@ -1,259 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace - -import 'dart:convert'; -import 'dart:typed_data'; -import 'package:file_selector/file_selector.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:universal_io/io.dart'; - -import 'package:http/http.dart'; -import 'package:http/http.dart' as http; -import 'package:rpmtranslator/API/APIs.dart'; -import 'package:rpmtranslator/API/RPMTWData.dart'; - -class CrowdinAPI { - static Future baseGet(String url, [headers_]) async { - Map headers = { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ${Account.getToken()}', - }; - if (headers_ != null) { - headers.addAll(headers_); - } - headers.addAll(RPMTWData.UserAgent); - Response response = await http.get(Uri.parse(url), headers: headers); - Map data = json.decode(response.body); - return data.containsKey('error') ? response : data['data']; - } - - static Future basePost(String url, dynamic body, [headers_]) async { - Map headers = { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ${Account.getToken()}' - }; - if (headers_ != null) { - headers.addAll(headers_); - } - headers.addAll(RPMTWData.UserAgent); - Response response = await http.post(Uri.parse(url), - headers: headers, body: body is Map ? json.encode(body) : body); - return response; - } - - static Future baseDelete(String url, [headers_]) async { - Map headers = { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ${Account.getToken()}', - }; - if (headers_ != null) { - headers.addAll(headers_); - } - headers.addAll(RPMTWData.UserAgent); - Response response = await http.delete(Uri.parse(url), headers: headers); - return response; - } - - static Future getMods( - String Version, String filter, int Page, String SortItem) async { - int DirID = RPMTWData.VersionDirID[Version] ?? 33894; - - switch (RPMTWData.SortItems.indexOf(SortItem)) { - case 0: //依照模組ID搜尋 - filter = filter == "" ? "" : "&filter=$filter"; - break; - case 1: //依照模組的CurseForge ID搜尋 - Map CrowdinIndex = - await RPMTWData.getCrowdinIndex(double.parse(Version)); - String ModID = ""; - if (CrowdinIndex.containsKey(filter)) { - ModID = CrowdinIndex[filter]['ModID']; - } - filter = ModID == "" ? "" : "&filter=$ModID"; - break; - default: - break; - } - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/directories?directoryId=$DirID&offset=${Page * 20}&limit=20$filter"; - dynamic data = await baseGet(url); - return data.runtimeType == Response - ? (data.statusCode == 401 - ? json.decode(data.body)['error']['message'] - : null) - : data; - } - - static Future getFilesByDir(int DirID, String filter, int Page) async { - filter = filter == "" ? "" : "&filter=$filter"; - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/files?directoryId=$DirID&recursion&offset=${Page * 20}&limit=20$filter"; - dynamic data = await baseGet(url); - return data; - } - - static Future getAllSourceString(String filter, int Page) async { - filter = filter == "" ? "" : "and (text=\"$filter\")"; - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/strings?offset=${Page * 20}&limit=20&croql=(count of translations = 0) $filter"; - dynamic data = await baseGet(url); - return data; - } - - static Future getSourceStringByFile( - int FileID, String filter, int Page) async { - filter = filter == "" ? "" : "&filter=$filter"; - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/strings?fileId=$FileID&offset=${Page * 20}&limit=20$filter"; - dynamic data = await baseGet(url); - return data; - } - - static Future addTranslation(int StringID, String text) async { - String url = "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/translations"; - Response response = await basePost(url, { - "stringId": StringID, - "languageId": RPMTWData.TraditionalChineseTaiwan, //繁體中文 - "text": text, - }); - Map data = json.decode(response.body); - return response.statusCode == 400 - ? data - : data.containsKey('error') - ? null - : data['data']; - } - - static Future getStringTranslations(int StringID) async { - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/translations?stringId=$StringID&languageId=${RPMTWData.TraditionalChineseTaiwan}&limit=20"; - dynamic data = await baseGet(url); - return data; - } - - static Future getProgressByFile(int FileID) async { - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/files/$FileID/languages/progress"; - List data = await baseGet(url); - Map Words = data[0]['data']['words']; - return Words['total'] == 0 && Words['translated'] == 0 - ? 0 - : Words['translated'] / Words['total']; - } - - static Future getProgressByDirectory(int FileID) async { - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/directories/$FileID/languages/progress"; - List data = await baseGet(url); - return data[0]['data']['translationProgress'] / 100; - } - - static Future getTranslationVotes( - int TranslationID, int StringID) async { - String url = - "$RPMCrowdinBaseAPI?url=/projects/${RPMTWData.CrowdinID}/votes/?translationId=$TranslationID&stringId=$StringID&languageId=${RPMTWData.TraditionalChineseTaiwan}"; - dynamic data = await baseGet(url, {'Access-Control-Allow-Headers': '*'}); - return data; - } - - static int prserVote(List Votes) { - int Num = 0; - Votes.forEach((Vote) { - if (Vote['data']['mark'] == "up") { - Num++; - } else if (Vote['data']['mark'] == "down") { - Num--; - } - }); - return Num; - } - - static Future addVote(int TranslationID, String mark) async { - String url = "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/votes"; - Response response = - await basePost(url, {"mark": mark, "translationId": TranslationID}); - Map data = json.decode(response.body); - - return data; - } - - static Future getCommentsByString(int StringID, int Page) async { - String url = - "$RPMCrowdinBaseAPI?url=/projects/${RPMTWData.CrowdinID}/comments/?stringId=$StringID&offset=${Page * 20}&limit=20"; - dynamic data = await baseGet(url, {'Access-Control-Allow-Headers': '*'}); - return data; - } - - static Future addComment(int StringID, String text, String Type, - [issueType]) async { - String url = "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/comments"; - - Map Json = { - "text": text, - "stringId": StringID, - "targetLanguageId": RPMTWData.TraditionalChineseTaiwan, - "type": Type - }; - - if (issueType != null) { - Json['issueType'] = issueType; - } - - Response response = await basePost(url, Json); - Map data = json.decode(response.body); - return response.statusCode == 400 - ? data - : data.containsKey('error') - ? null - : data['data']; - } - - static Future updateTranslation( - XFile file, int FileID, String FileName) async { - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/translations/${RPMTWData.TraditionalChineseTaiwan}"; - - int? storageId = - await CrowdinAPI.addStorage(await file.readAsBytes(), FileName); - - if (storageId == null) return false; - - Map Json = {"storageId": storageId, "fileId": FileID}; - - Response response = await basePost(url, Json); - Map data = json.decode(response.body); - return response.statusCode == 200 ? true : false; - } - - static Future addStorage(Uint8List fileBytes, String FileName) async { - String url = "$CrowdinBaseAPI/storages"; - - Response response = await basePost(url, fileBytes, { - "Crowdin-API-FileName": FileName, - "Content-Type": "application/octet-stream" - }); - Map data = json.decode(response.body); - return response.statusCode == 201 ? data['data']['id'] : null; - } - - static Future downloadFile( - int FileID, String path, String FileName) async { - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/files/$FileID/download"; - - Map data = await baseGet(url); - String downloadUrl = data['url']; - await http.get(Uri.parse(downloadUrl)).then((response) async { - final file = XFile.fromData(response.bodyBytes, name: FileName); - await file.saveTo(path); - }); - return true; - } - - static Future deleteTranslation(int translationId) async { - String url = - "$CrowdinBaseAPI/projects/${RPMTWData.CrowdinID}/translations/$translationId"; - Response response = await baseDelete(url); - print(response.statusCode == 204); - return response.statusCode == 204; - } -} diff --git a/lib/API/RPMTWData.dart b/lib/API/RPMTWData.dart deleted file mode 100644 index 6d8f624..0000000 --- a/lib/API/RPMTWData.dart +++ /dev/null @@ -1,108 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, prefer_const_literals_to_create_immutables - -import 'dart:collection'; -import 'dart:convert'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:highlight_text/highlight_text.dart'; -import 'package:http/http.dart'; -import 'package:rpmtranslator/API/APIs.dart'; -import 'package:rpmtranslator/Widget/HighlightedWord.dart'; - -class RPMTWData { - static final List VersionItems = ["1.17", "1.16", "1.12"]; - static final List SortItems = [ - "模組 ID", - "CurseForge ID", - ]; - static Map VersionDirID = { - "1.12": 37104, - "1.16": 14698, - "1.17": 33894 - }; - static Map VersionsSha = { - "1.12": "Translated-1.12", - "1.16": "Translated", - "1.17": "Translated-1.17" - }; - static int CrowdinID = 442446; - static String TraditionalChineseTaiwan = 'zh-TW'; - static String MarkUp = 'up'; - static String MarkDown = 'down'; - static Map UserAgent = {'User-Agent': 'RPMTranslator'}; - static String Comment = 'comment'; - static String CommentIssue = 'issue'; - - static Map ErrorMessage = { - "Forbidden": "沒有存取權限", - "An identical translation of this string has been already saved. Vote for the existing translation instead of adding a new one.": - "存在重複的翻譯" - }; - - static LinkedHashMap HighlightedWords = { - "%s": RPMHighlightedWord( - onTap: () {}, - tooltip: "格式化字串請勿翻譯", - textStyle: TextStyle( - color: Color.fromRGBO(175, 253, 137, 1.0), - backgroundColor: Color.fromRGBO(143, 160, 122, 1.0), - ), - decoration: BoxDecoration()), - "%d": RPMHighlightedWord( - onTap: () {}, - tooltip: "格式化字串請勿翻譯", - textStyle: TextStyle( - color: Color.fromRGBO(175, 253, 137, 1.0), - backgroundColor: Color.fromRGBO(143, 160, 122, 1.0), - ), - decoration: BoxDecoration()), - } as LinkedHashMap; - - static Future getProgress() async { - Response response = await get(Uri.parse(RPMTWProgressAPI)); - Map data = json.decode(response.body); - return data; - } - - static Future getContribution() async { - Response response = await get(Uri.parse(RPMTWContributionAPI)); - List data = json.decode(response.body)['data']; - return data; - } - - static Future getCurseForgeIndex(double VersionID) async { - String GitVersion = VersionID == 1.16 ? "Original" : "Original-$VersionID"; - Response response = await get(Uri.parse( - "https://raw.githubusercontent.com/RPMTW/ResourcePack-Mod-zh_tw/$GitVersion/$VersionID/ModInfo.json")); - Map data = json.decode(response.body); - return data; - } - - static Future getCrowdinIndex(double VersionID) async { - Response response = await get(Uri.parse( - "https://raw.githubusercontent.com/RPMTW/RPMTW-website-data/main/data/CrowdinIndex-$VersionID.json")); - Map data = json.decode(response.body); - return data; - } - - static Future getCurseForgeAddonInfo(int CurseID) async { - if (CurseID == 0) return {}; - Response response = await get( - Uri.parse("$CurseForgeAPI?url=addon/$CurseID"), - headers: {'Access-Control-Allow-Headers': '*'}); - Map data = json.decode(response.body); - return data; - } - - static String TranslateErrorMessage(String Error) { - return ErrorMessage.containsKey(Error) - ? ErrorMessage[Error].toString() - : Error; - } - - static String FormatIsoTime(String IsoTime) { - DateTime Time = DateTime.parse(IsoTime); - - return "${Time.year}年${Time.month}月${Time.day}日${Time.hour}時${Time.minute}分鐘${Time.second}秒"; - } -} diff --git a/lib/API/TranslationAPI.dart b/lib/API/TranslationAPI.dart deleted file mode 100644 index 5c4253f..0000000 --- a/lib/API/TranslationAPI.dart +++ /dev/null @@ -1,15 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace, no_logic_in_create_state, curly_braces_in_flow_control_structures, unrelated_type_equality_checks, constant_identifier_names - -import 'dart:convert'; - -import 'package:http/http.dart'; - -class TranslationAPI { - static Future TranslationWithModernMT(String SrcText) async { - Response response = await get(Uri.parse( - "https://webapi.modernmt.com/translate?source=en&target=zh-TW&q=$SrcText")); - - Map data = json.decode(response.body); - return response.statusCode == 200 ? data['data']['translation'] : null; - } -} diff --git a/lib/Account/Account.dart b/lib/Account/Account.dart deleted file mode 100644 index 7e3c947..0000000 --- a/lib/Account/Account.dart +++ /dev/null @@ -1,109 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_final_fields - -import 'dart:convert'; -import 'package:universal_html/html.dart'; - -import 'package:flutter/foundation.dart'; -import 'package:rpmtranslator/main.dart'; - -import '../path.dart'; -import 'package:universal_io/io.dart' as io; -import 'package:path/path.dart'; - -class Account { - static io.Directory _ConfigFolder = configHome; - static io.File AccountFile = - io.File(join(_ConfigFolder.absolute.path, "accounts.json")); - static Map _account = json.decode(AccountFile.readAsStringSync()); - - static Map get() { - return _account; - } - - static void add(String Token, String RefreshToken, int UserID) { - if (kIsWeb) { - window.localStorage.addAll({ - "AccessToken": Token, - "RefreshToken": RefreshToken, - "UserID": UserID.toString(), - "Expired": false.toString() - }); - } else { - _account = { - "AccessToken": Token, - "RefreshToken": RefreshToken, - "UserID": UserID, - "Expired": false - }; - } - save(); - } - - static bool has() { - if (kIsWeb) { - return window.localStorage.containsKey("AccessToken"); - } else { - return _account.containsKey("AccessToken"); - } - } - - static bool expired() { - if (kIsWeb) { - return window.localStorage.containsKey('Expired') - ? window.localStorage["Expired"].toString().parseBool() - : false; - } else { - return _account.containsKey('Expired') ? _account["Expired"] : false; - } - } - - static void setExpired(bool s) { - if (kIsWeb) { - window.localStorage["Expired"] = s.toString(); - } else { - _account["Expired"] = s; - } - save(); - } - - static String getToken() { - if (kIsWeb) { - return window.localStorage["AccessToken"].toString(); - } else { - return _account["AccessToken"]; - } - } - - static String getRefreshToken() { - if (kIsWeb) { - return window.localStorage["RefreshToken"].toString(); - } else { - return _account["RefreshToken"]; - } - } - - static int getUserID() { - if (kIsWeb) { - return int.parse(window.localStorage["UserID"].toString()); - } else { - return _account["UserID"]; - } - } - - static void logout() { - if (kIsWeb) return window.localStorage.clear(); - _account = {}; - save(); - } - - static void save() { - if (kIsWeb) return; - AccountFile.writeAsStringSync(json.encode(_account)); - } - - static void change(Map Json) { - if (kIsWeb) return window.localStorage.addAll(Json.cast()); - _account = Json; - save(); - } -} diff --git a/lib/Account/CrowdinAuth.dart b/lib/Account/CrowdinAuth.dart deleted file mode 100644 index d7da581..0000000 --- a/lib/Account/CrowdinAuth.dart +++ /dev/null @@ -1,62 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print - -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http/http.dart'; -import 'package:rpmtranslator/API/RPMTWData.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:universal_html/html.dart'; - -class CrowdinAuthHandler { - /* - API Docs: https://support.crowdin.com/api/v2/ - */ - - static String Success = 'success'; - static String Error = 'error'; - - static Future CheckToken(String accessToken) async { - var headers = { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer $accessToken' - }; - var request = - http.Request('GET', Uri.parse('https://api.crowdin.com/api/v2/user')); - request.body = json.encode({}); - request.headers.addAll(headers); - - http.StreamedResponse response = await request.send(); - if (response.statusCode == 200) { - Map data = json.decode(await response.stream.bytesToString()); - return [Success, data]; - } else { - print(response.reasonPhrase); - return []; - } - } - - static Future RefreshToken(String refreshToken) async { - Map headers = { - 'Access-Control-Allow-Origin': '*', - 'Content-Type': 'application/json', - }; - headers.addAll(RPMTWData.UserAgent); - Response response = await http.get( - Uri.parse( - "https://rear-end.a102009102009.repl.co/crowdin/auth/refreshToken?refreshToken=$refreshToken"), - headers: headers, - ); - Map data = json.decode(response.body); - if (response.statusCode == 200) { - window.localStorage.addAll({ - "AccessToken": data["access_token"].toString(), - "RefreshToken": data['refresh_token'].toString(), - "UserID": Account.getUserID().toString(), - "Expired": false.toString() - }); - return true; - } else { - return false; - } - } -} diff --git a/lib/Screen/AccountWeb.dart b/lib/Screen/AccountWeb.dart deleted file mode 100644 index 3c77002..0000000 --- a/lib/Screen/AccountWeb.dart +++ /dev/null @@ -1,71 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element -import 'package:flutter/material.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Account/CrowdinAuth.dart'; -import 'package:rpmtranslator/Utility/utility.dart'; -import 'package:universal_html/html.dart'; - -import '../main.dart'; - -class AccountWebScreen_ extends State { - bool _obscureText = true; - - TextEditingController TokenController = TextEditingController(); - - @override - void initState() { - super.initState(); - setState(() {}); - } - - var title_ = TextStyle( - fontSize: 20.0, - ); - - @override - Widget build(BuildContext context) { - return Builder(builder: (context) { - if (Account.has() && !Account.expired()) { - //已經有帳號了,並且該帳號沒有過期 - return AlertDialog( - title: Text("您已經登入過帳號了"), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text("關閉此頁面")), - TextButton( - onPressed: () { - Account.logout(); - Navigator.pop(context); - }, - child: Text("登出帳號")) - ], - ); - } else { - return AlertDialog( - title: Text("登入 Crowdin 帳號", textAlign: TextAlign.center), - content: Text("點擊下方的登入按鈕將會開啟 Crowdin 的授權網頁,請在該網頁上登入帳號"), - actions: [ - IconButton( - icon: Icon(Icons.login), - onPressed: () { - window.open( - "https://accounts.crowdin.com/oauth/authorize?client_id=8HpxK2jINouRXTrVq6gf&redirect_uri=https://rear-end.a102009102009.repl.co/crowdin/oauth/auth/web&response_type=code&scope=project", - "", - "width=500,height=620"); - }, - tooltip: "登入", - ), - ], - ); - } - }); - } -} - -class AccountWebScreen extends StatefulWidget { - @override - AccountWebScreen_ createState() => AccountWebScreen_(); -} diff --git a/lib/Screen/Contribution.dart b/lib/Screen/Contribution.dart deleted file mode 100644 index b69b53b..0000000 --- a/lib/Screen/Contribution.dart +++ /dev/null @@ -1,125 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; -import 'package:rpmtranslator/API/RPMTWData.dart'; -import 'package:rpmtranslator/Widget/OkClose.dart'; -import 'package:url_launcher/url_launcher.dart'; - -import '../main.dart'; - -class ContributionScreen_ extends State { - TextEditingController TokenController = TextEditingController(); - @override - void initState() { - super.initState(); - setState(() {}); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("翻譯貢獻者排名 (一個月內)"), - leading: IconButton( - icon: Icon(Icons.arrow_back), - tooltip: "返回", - onPressed: () { - Navigator.pushNamed( - context, - HomePage.route, - ); - }, - ), - centerTitle: true, - ), - body: Container( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - child: FutureBuilder( - future: RPMTWData.getContribution(), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - return ListView.builder( - itemCount: snapshot.data.length, - itemBuilder: (context, index) { - Map data = snapshot.data[index]; - Map user = data["user"]; - return DecoratedBox( - decoration: BoxDecoration( - border: Border.all(color: Colors.white12, width: 1), - ), - child: ListTile( - leading: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text((index + 1).toString(), - style: TextStyle( - fontSize: 30, color: Colors.blue)), - SizedBox( - width: 10, - ), - ClipRRect( - borderRadius: BorderRadius.circular(50), - child: Image.network(user['avatarUrl']), - ), - ], - ), - title: Text(user['fullName'], - style: TextStyle(fontSize: 30), - textAlign: TextAlign.center), - onTap: () { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text("詳細資訊", - textAlign: TextAlign.center), - content: Column( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "翻譯字數: ${data['translated']}", - ), - Text( - "投票次數: ${data['voted']}", - ), - Text( - "翻譯獲得稱讚次數: ${data['winning']}", - ), - Text( - "加入時間: ${RPMTWData.FormatIsoTime(user['joined'])}", - ), - ], - ), - actions: [ - TextButton( - onPressed: () { - launch( - "https://crowdin.com/profile/${user['username']}"); - }, - child: Text("在Crowdin上查看")), - OkClose() - ], - ); - }); - }, - ), - ); - }); - } else { - return Center(child: CircularProgressIndicator()); - } - })), - ); - } -} - -class ContributionScreen extends StatefulWidget { - static String route = "/contribution"; - @override - ContributionScreen_ createState() => ContributionScreen_(); -} diff --git a/lib/Screen/CrowdinOauth.dart b/lib/Screen/CrowdinOauth.dart deleted file mode 100644 index dce6c15..0000000 --- a/lib/Screen/CrowdinOauth.dart +++ /dev/null @@ -1,195 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element -/* -The code here is referenced from https://codelabs.developers.google.com/codelabs/flutter-MS-graphql-client - */ - -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:rpmtranslator/Utility/utility.dart'; -import 'package:universal_io/io.dart'; - -import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; -import 'package:oauth2/oauth2.dart' as oauth2; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Account/CrowdinAuth.dart'; -import 'package:url_launcher/url_launcher.dart'; - -import '../main.dart'; - -final _authorizationEndpoint = - Uri.parse('https://accounts.crowdin.com/oauth/authorize'); -final _tokenEndpoint = Uri.parse('https://accounts.crowdin.com/oauth/token'); - -class CrowdinAuthScreen extends StatefulWidget { - const CrowdinAuthScreen({Key? key}) : super(key: key); - - @override - _CrowdinOauthState createState() => _CrowdinOauthState(); -} - -typedef AuthenticatedBuilder = Widget Function( - BuildContext context, oauth2.Client client); - -class _CrowdinOauthState extends State { - HttpServer? _redirectServer; - oauth2.Client? _client; - - @override - Widget build(BuildContext context) { - final client = _client; - if (client != null) { - return FutureBuilder( - future: CrowdinAuthHandler.CheckToken(client.credentials.accessToken), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData && - snapshot.data[0] == CrowdinAuthHandler.Success) { - Account.add( - client.credentials.accessToken, - client.credentials.refreshToken.toString(), - snapshot.data[1]['data']['id']); - return AlertDialog( - title: Text("登入成功", textAlign: TextAlign.center), - actions: [ - IconButton( - icon: Icon(Icons.close), - tooltip: "確定", - onPressed: () { - Navigator.pushNamed(context, HomePage.route); - }, - ) - ], - ); - } else if (snapshot.hasData && - snapshot.data[0] == CrowdinAuthHandler.Error) { - return AlertDialog( - title: Text("登入失敗", textAlign: TextAlign.center), - content: Text("登入權杖錯誤,請嘗試再次登入,如果仍然失敗,請至 RPMTW Discord 伺服器詢問。", - textAlign: TextAlign.center), - actions: [ - IconButton( - icon: Icon(Icons.refresh), - tooltip: "重新登入", - onPressed: () { - Navigator.pop(context); - Navigator.pop(context); - utility.IsWebAccount(context); - }, - ) - ], - ); - } else { - return AlertDialog( - title: Text("正在處理帳號資料中...", textAlign: TextAlign.center), - content: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 12, - ), - CircularProgressIndicator(), - SizedBox( - height: 12, - ), - ], - ), - ); - } - }); - } - if (Account.has() && !Account.expired()) { - //已經有帳號了,並且該帳號沒有過期 - return AlertDialog( - title: Text("您已經登入過帳號了"), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text("關閉此頁面")), - TextButton( - onPressed: () { - Account.logout(); - Navigator.pop(context); - }, - child: Text("登出帳號")) - ], - ); - } else { - return Center( - child: AlertDialog( - title: Text("登入您的 Crowdin 帳號 ", textAlign: TextAlign.center), - content: Text( - "點擊下方的 確定 按鈕後,將會開啟一個網站,請在該網站上登入 Crowdin 帳號", - textAlign: TextAlign.center, - style: new TextStyle(fontSize: 20), - ), - actions: [ - Center( - child: ElevatedButton( - onPressed: () async { - await _redirectServer?.close(); - _redirectServer = await HttpServer.bind('127.0.0.1', 5000); - var authenticatedHttpClient = await _getOAuth2Client(Uri.parse( - 'http://127.0.0.1:${_redirectServer!.port}/rpmtranslator-auth')); - setState(() { - _client = authenticatedHttpClient; - }); - }, - child: Text("確定"), - ), - ) - ], - )); - } - } - - Future _getOAuth2Client(Uri redirectUrl) async { - var grant = oauth2.AuthorizationCodeGrant( - "hxk05Ij1xVFDEemvb2Ra", //Client ID - _authorizationEndpoint, - _tokenEndpoint, - secret: 'l6maTnuFjLwqx9nDAbCiB42CHTzqyJnPko9qzRrv', - httpClient: _JsonAcceptingHttpClient(), - ); - var authorizationUrl = - grant.getAuthorizationUrl(redirectUrl, scopes: ['project']); - await _redirect(authorizationUrl); - Map responseQueryParameters = await _listen(); - oauth2.Client client = - await grant.handleAuthorizationResponse(responseQueryParameters); - return client; - } - - Future _redirect(authorizationUrl) async { - var url = authorizationUrl.toString(); - if (await canLaunch(url)) { - await launch(url); - } else { - print("Can't open the url $url"); - } - } - - Future> _listen() async { - var request = await _redirectServer!.first; - var params = request.uri.queryParameters; - request.response.statusCode = 200; - request.response.headers.set('content-type', 'text/plain; charset=utf-8'); - request.response.writeln('驗證完畢,請回到 RPMTranslator 內。'); - await request.response.close(); - await _redirectServer!.close(); - _redirectServer = null; - return params; - } -} - -class _JsonAcceptingHttpClient extends http.BaseClient { - final _httpClient = http.Client(); - - @override - Future send(http.BaseRequest request) { - request.headers['Accept'] = 'application/json'; - return _httpClient.send(request); - } -} diff --git a/lib/Screen/DownloadFile.dart b/lib/Screen/DownloadFile.dart deleted file mode 100644 index 89474dc..0000000 --- a/lib/Screen/DownloadFile.dart +++ /dev/null @@ -1,83 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace, no_logic_in_create_state - -import 'package:universal_io/io.dart'; - -import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:rpmtranslator/API/CrowdinAPI.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Widget/OkClose.dart'; -import 'package:path/path.dart' as Path; - -class DownloadFile extends StatefulWidget { - final int FileID; - final String FileName; - const DownloadFile({ - required this.FileID, - required this.FileName, - Key? key, - }) : super(key: key); - - @override - State createState() => - _DownloadFileState(FileID: FileID, FileName: FileName); -} - -class _DownloadFileState extends State { - final int FileID; - final String FileName; - _DownloadFileState({required this.FileID, required this.FileName}); - - @override - Widget build(BuildContext context) { - return AlertDialog(title: Text("下載檔案"), actions: [ - TextButton( - onPressed: () async { - final String? path = await FileSelectorPlatform.instance - .getSavePath(acceptedTypeGroups: [ - XTypeGroup( - label: "下載的檔案類型", extensions: [Path.extension(FileName)]) - ]); - if (path != null) { - Navigator.pop(context); - showDialog( - barrierDismissible: false, - context: context, - builder: (context) { - return FutureBuilder( - future: CrowdinAPI.downloadFile(FileID, path, FileName), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData && snapshot.data) { - return AlertDialog( - title: Text("下載檔案完成"), - actions: [OkClose()], - ); - } else { - return AlertDialog( - title: Text("正在從 Crowdin 伺服器下載檔案中..."), - content: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 20, - ), - CircularProgressIndicator(), - SizedBox( - height: 20, - ) - ], - ), - ); - } - }); - }); - } else { - return; - } - }, - child: Text("下載")) - ]); - } -} diff --git a/lib/Screen/Files.dart b/lib/Screen/Files.dart deleted file mode 100644 index d94a188..0000000 --- a/lib/Screen/Files.dart +++ /dev/null @@ -1,265 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace, no_logic_in_create_state -import 'package:flutter/material.dart'; -import 'package:rpmtranslator/API/CrowdinAPI.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Widget/AccountNone.dart'; -import 'package:split_view/split_view.dart'; - -import 'DownloadFile.dart'; -import 'Translate.dart'; -import 'UploadTranslation.dart'; - -class FilesScreen_ extends State { - final TextEditingController SearchController = TextEditingController(); - final ScrollController FilesScrollController = ScrollController(); - final PageController FilesPageController = PageController(initialPage: 0); - int FilesListLength = 0; - int Page = 0; - late StateSetter setChangePageState; - - final int DirID; - - FilesScreen_({required this.DirID}); - @override - void initState() { - super.initState(); - } - - var title_ = TextStyle( - fontSize: 20.0, - ); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("檔案選擇頁面"), - leading: IconButton( - icon: Icon(Icons.arrow_back), - tooltip: "返回", - onPressed: () { - Navigator.pop(context); - }, - ), - centerTitle: true, - ), - body: SplitView( - gripSize: 0, - controller: SplitViewController(weights: [0.1, 0.8, 0.1]), - viewMode: SplitViewMode.Vertical, - children: [ - Container( - child: Column( - children: [ - SizedBox( - height: 20, - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 30, - ), - Text( - "搜尋檔案", - style: title_, - ), - SizedBox( - width: 12, - ), - Expanded( - child: TextField( - textAlign: TextAlign.center, - controller: SearchController, - decoration: InputDecoration( - hintText: "請輸入檔案名稱", - enabledBorder: OutlineInputBorder( - borderSide: - BorderSide(color: Colors.lightBlue, width: 5.0), - ), - focusedBorder: OutlineInputBorder( - borderSide: - BorderSide(color: Colors.lightBlue, width: 3.0), - ), - contentPadding: EdgeInsets.zero, - border: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - ), - )), - SizedBox( - width: 12, - ), - ElevatedButton( - style: new ButtonStyle( - backgroundColor: MaterialStateProperty.all( - Colors.deepPurpleAccent)), - onPressed: () { - FilesPageController.animateToPage(0, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300)); - setState(() {}); - }, - child: Text( - "搜尋", - style: title_, - ), - ), - SizedBox( - width: 30, - ), - ], - ), - ], - ), - ), - Container( - child: PageView.builder( - controller: FilesPageController, - scrollDirection: Axis.horizontal, - itemBuilder: (context, int Page_) { - Page = Page_; - return FutureBuilder( - future: CrowdinAPI.getFilesByDir( - DirID, SearchController.text, Page_), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData && snapshot.data != null) { - return ListView.builder( - shrinkWrap: true, - controller: FilesScrollController, - itemCount: snapshot.data.length, - itemBuilder: (context, int Index) { - FilesListLength = snapshot.data.length; - Map data = snapshot.data[Index]['data']; - String FileName = data['name'].toString(); - FileName == "zh_tw.json" - ? FileName = "主要語系檔案" - : FileName; - return ListTile( - title: Text(FileName, - textAlign: TextAlign.center), - onTap: () { - int CrowdinFileID = data['id']; - showDialog( - routeSettings: RouteSettings( - name: - "${ModalRoute.of(context)!.settings.name}/$CrowdinFileID/translate?FileName=$FileName", - ), - context: context, - builder: (context) => TranslateScreen( - FileID: CrowdinFileID, - FileName: FileName)); - }, - trailing: PopupMenuButton( - tooltip: "顯示更多", - itemBuilder: (context) => [ - PopupMenuItem( - child: Text("翻譯"), - value: 1, - ), - PopupMenuItem( - child: Text("上傳翻譯"), - value: 2, - ), - PopupMenuItem( - child: Text("下載檔案"), - value: 3, - ) - ], - onSelected: (int Index) { - switch (Index) { - case 1: - showDialog( - context: context, - builder: (context) => - TranslateScreen( - FileID: data['id'], - FileName: FileName)); - break; - case 2: - showDialog( - context: context, - builder: (context) => - UploadTranslation( - FileID: data['id'], - FileName: - data['name'])); - break; - case 3: - showDialog( - context: context, - builder: (context) => - DownloadFile( - FileID: data['id'], - FileName: data['name'], - )); - break; - default: - break; - } - }), - ); - }); - } else if (snapshot.hasData && - snapshot.data == null) { - return AccountNone(); - } else if (snapshot.hasError) { - return Text(snapshot.error.toString()); - } else { - return Center(child: CircularProgressIndicator()); - } - }); - }), - ), - StatefulBuilder(builder: (context, setChangePageState_) { - setChangePageState = setChangePageState_; - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - tooltip: "上一頁", - onPressed: () async { - await FilesPageController.animateToPage( - FilesPageController.page!.toInt() - 1, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300)); - setChangePageState_(() {}); - }, - icon: Icon(Icons.navigate_before)), - SizedBox( - width: 20, - ), - Text( - (Page + 1).toString(), - style: TextStyle(fontSize: 18), - ), - SizedBox( - width: 20, - ), - IconButton( - tooltip: "下一頁", - onPressed: () async { - if (FilesListLength < 20) return; - await FilesPageController.animateToPage( - FilesPageController.page!.toInt() + 1, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300)); - setChangePageState_(() {}); - }, - icon: Icon(Icons.navigate_next)) - ], - ); - }) - ]), - ); - } -} - -class FilesScreen extends StatefulWidget { - final int DirID; - - const FilesScreen({required this.DirID}); - - @override - FilesScreen_ createState() => FilesScreen_(DirID: DirID); -} diff --git a/lib/Screen/Mods.dart b/lib/Screen/Mods.dart deleted file mode 100644 index c789f5e..0000000 --- a/lib/Screen/Mods.dart +++ /dev/null @@ -1,390 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:rpmtranslator/API/CrowdinAPI.dart'; -import 'package:rpmtranslator/API/RPMTWData.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Screen/Files.dart'; -import 'package:rpmtranslator/Utility/utility.dart'; -import 'package:rpmtranslator/Widget/AccountNone.dart'; -import 'package:rpmtranslator/Widget/OkClose.dart'; -import 'package:split_view/split_view.dart'; - -import '../main.dart'; -import 'Translate.dart'; - -class ModsScreen_ extends State { - final TextEditingController SearchController = TextEditingController(); - final ScrollController ModScrollController = ScrollController(); - final PageController ModPageController = PageController(initialPage: 0); - final List VersionItems = RPMTWData.VersionItems; - final List SortItems = RPMTWData.SortItems; - String VersionItem = "1.17"; - String SortItem = RPMTWData.SortItems[0]; - int ModListLength = 0; - int Page = 0; - late StateSetter setChangePageState; - - @override - void initState() { - super.initState(); - } - - var title_ = TextStyle( - fontSize: 20.0, - ); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("模組翻譯頁面"), - leading: IconButton( - icon: Icon(Icons.arrow_back), - tooltip: "返回", - onPressed: () { - Navigator.pushNamed(context, HomePage.route); - }, - ), - centerTitle: true, - ), - body: SplitView( - gripSize: 0, - controller: SplitViewController(weights: [0.15, 0.75, 0.1]), - viewMode: SplitViewMode.Vertical, - children: [ - Container( - child: Column( - children: [ - SizedBox( - height: 20, - ), - TextButton( - onPressed: () { - showDialog(context: context, builder: (context) => TranslateScreen(FileID: null, FileName: null)); - String test; - }, - child: Text( - "翻譯全部", - style: TextStyle(fontSize: 25), - ), - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 30, - ), - Text( - "搜尋模組", - style: title_, - ), - SizedBox( - width: 12, - ), - Expanded( - child: TextField( - textAlign: TextAlign.center, - controller: SearchController, - decoration: InputDecoration( - hintText: "請輸入 $SortItem", - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.white12, width: 3.0), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.lightBlue, width: 3.0), - ), - contentPadding: EdgeInsets.zero, - border: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - ), - )), - SizedBox( - width: 12, - ), - ElevatedButton( - style: new ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.deepPurpleAccent)), - onPressed: () { - ModPageController.animateToPage(0, curve: Curves.easeOut, duration: const Duration(milliseconds: 300)); - setState(() {}); - }, - child: Text( - "搜尋", - style: title_, - ), - ), - SizedBox( - width: 12, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "遊戲版本", - style: title_, - ), - DropdownButton( - value: VersionItem, - style: TextStyle(color: Colors.white), - onChanged: (String? newValue) { - VersionItem = newValue.toString(); - ModPageController.animateToPage(0, curve: Curves.easeOut, duration: const Duration(milliseconds: 300)); - setState(() {}); - }, - items: VersionItems.map>((String value) { - return DropdownMenuItem( - value: value, - child: Text( - value, - textAlign: TextAlign.center, - style: title_, - ), - ); - }).toList(), - ), - ], - ), - SizedBox( - width: 30, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "搜尋類型", - style: title_, - ), - DropdownButton( - value: SortItem, - alignment: Alignment.center, - style: TextStyle(color: Colors.white), - onChanged: (String? newValue) { - SortItem = newValue.toString(); - setState(() {}); - }, - items: SortItems.map>((String value) { - return DropdownMenuItem( - value: value, - alignment: Alignment.center, - child: Text( - value, - textAlign: TextAlign.center, - style: title_, - ), - ); - }).toList(), - ), - ], - ), - SizedBox( - width: 30, - ), - ], - ), - ], - ), - ), - Container( - child: FutureBuilder( - future: RPMTWData.getCurseForgeIndex(double.parse(VersionItem)), - builder: (context, AsyncSnapshot CurseIndexSnapshot) { - if (CurseIndexSnapshot.hasData) { - Map CurseIndex = CurseIndexSnapshot.data!; - return PageView.builder( - controller: ModPageController, - scrollDirection: Axis.horizontal, - itemBuilder: (context, int Page_) { - Page = Page_; - return FutureBuilder( - future: CrowdinAPI.getMods(VersionItem, SearchController.text, Page_, SortItem), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData && snapshot.data is List) { - return ListView.builder( - shrinkWrap: true, - controller: ModScrollController, - itemCount: snapshot.data.length, - itemBuilder: (context, int Index) { - ModListLength = snapshot.data.length; - Map data = snapshot.data[Index]['data']; - String DirName = data['name'].toString(); - int CurseID = CurseIndex.containsKey(DirName) ? CurseIndex[DirName]['curseForgeID'] : 0; - return FutureBuilder( - future: RPMTWData.getCurseForgeAddonInfo(CurseID), - builder: (context, AsyncSnapshot CurseAddonSnapshot) { - if (CurseAddonSnapshot.hasData) { - bool IsCurseMod = CurseAddonSnapshot.data != {} && CurseIndex.containsKey(DirName); - return Column( - children: [ - SizedBox(height: 5), - ListTile( - leading: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 50, - height: 50, - child: ClipRRect( - borderRadius: BorderRadius.circular(100.0), - child: FutureBuilder( - future: CrowdinAPI.getProgressByDirectory(data['id']), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - return Stack(children: [ - RotatedBox( - quarterTurns: 3, - child: LinearProgressIndicator( - color: Colors.blue, - value: snapshot.data, - minHeight: 50, - ), - ), - Positioned( - child: Text("${(snapshot.data * 100).toInt()}%", - textAlign: TextAlign.center), - top: 15, - left: 0, - bottom: 15, - right: 0, - ) - ]); - } else { - return LinearProgressIndicator(); - } - }), - ), - ), - SizedBox( - width: 10, - ), - SizedBox( - width: 50, - height: 50, - child: ClipRRect( - borderRadius: BorderRadius.circular(8.0), - child: Builder(builder: (context) { - if (IsCurseMod) { - Map? CurseAddonInfo = CurseAddonSnapshot.data; - if (CurseAddonInfo!.containsKey('attachments') && - CurseAddonInfo['attachments'].isNotEmpty) { - return Image.network(CurseAddonInfo['attachments'][0]['thumbnailUrl'], - fit: BoxFit.fill); - } else { - return Icon(Icons.image, size: 50); - } - } else { - return Icon(Icons.image, size: 50); - } - }), - ), - ), - ], - ), - title: Text(DirName), - onTap: () { - int CrowdinDirID = data['id']; - showDialog( - routeSettings: RouteSettings(name: "/mods/$CrowdinDirID/files"), - context: context, - builder: (context) => FilesScreen(DirID: CrowdinDirID)); - }, - trailing: SizedBox( - width: 50, - height: 50, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Builder(builder: (context) { - if (IsCurseMod) { - Map? CurseAddonInfo = CurseAddonSnapshot.data; - return IconButton( - onPressed: () { - utility.OpenUrl(CurseAddonInfo!['websiteUrl']); - }, - icon: Icon(Icons.open_in_browser), - tooltip: "在 CurseForge 檢視此模組", - ); - } else { - return Container(); - } - }), - ], - ), - )), - SizedBox(height: 5), - ], - ); - } else { - return Center(child: CircularProgressIndicator()); - } - }); - }); - } else if (snapshot.hasData && snapshot.data is String && snapshot.data == "Unauthorized") { - Account.setExpired(true); - return AccountNone(); - } else if (snapshot.hasData && snapshot.data is Map && snapshot.data.containsKey('error')) { - return AlertDialog( - title: Text("取得模組失敗"), - content: Text("錯誤原因: ${RPMTWData.TranslateErrorMessage(snapshot.data!['error']['message'])}"), - actions: [OkClose()], - ); - } else if (snapshot.hasError) { - return Text(snapshot.error.toString()); - } else { - return Center(child: CircularProgressIndicator()); - } - }); - }); - } else { - return Center(child: CircularProgressIndicator()); - } - })), - StatefulBuilder(builder: (context, setChangePageState_) { - setChangePageState = setChangePageState_; - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - tooltip: "上一頁", - onPressed: () async { - await ModPageController.animateToPage(ModPageController.page!.toInt() - 1, - curve: Curves.easeOut, duration: const Duration(milliseconds: 300)); - setChangePageState_(() {}); - }, - icon: Icon(Icons.navigate_before)), - SizedBox( - width: 20, - ), - Text( - (Page + 1).toString(), - style: TextStyle(fontSize: 18), - ), - SizedBox( - width: 20, - ), - IconButton( - tooltip: "下一頁", - onPressed: () async { - if (ModListLength < 20) return; - await ModPageController.animateToPage(ModPageController.page!.toInt() + 1, - curve: Curves.easeOut, duration: const Duration(milliseconds: 300)); - setChangePageState_(() {}); - }, - icon: Icon(Icons.navigate_next)) - ], - ); - }), - ], - ), - ); - } -} - -class ModsScreen extends StatefulWidget { - static String route = "/mods"; - @override - ModsScreen_ createState() => ModsScreen_(); -} diff --git a/lib/Screen/Progress.dart b/lib/Screen/Progress.dart deleted file mode 100644 index 5c572fe..0000000 --- a/lib/Screen/Progress.dart +++ /dev/null @@ -1,184 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; -import 'package:rpmtranslator/API/RPMTWData.dart'; - -import '../main.dart'; - -class ProgressScreen_ extends State { - TextEditingController TokenController = TextEditingController(); - @override - void initState() { - super.initState(); - setState(() {}); - } - - var title_ = TextStyle( - fontSize: 20.0, - ); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("模組翻譯進度"), - leading: IconButton( - icon: Icon(Icons.arrow_back), - tooltip: "返回", - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => App()), - ); - }, - ), - centerTitle: true, - ), - body: Center( - child: FutureBuilder( - future: RPMTWData.getProgress(), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - Size size = MediaQuery.of(context).size; - - Map data = snapshot.data; - return Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - ProgressCard( - Title: "全版本", - Values: data['progress'], - progress: data['progress'], - size: size), - ProgressCard( - Title: "1.12", - Values: data['1.12'], - progress: data['1.12'], - size: size), - ProgressCard( - Title: "1.16", - Values: data['1.16'], - progress: data['1.16'], - size: size), - ProgressCard( - Title: "1.17", - Values: data['1.17'], - progress: data['1.17'], - size: size), - ], - ); - } else { - return Center(child: CircularProgressIndicator()); - } - })), - ); - } -} - -class ProgressCard extends StatefulWidget { - final String Title; - final String Values; - final String progress; - final Size size; - - const ProgressCard({ - required this.Title, - required this.Values, - required this.progress, - required this.size, - }); - - @override - // ignore: no_logic_in_create_state - ProgressCard_ createState() => ProgressCard_( - Title: Title, Values: Values, progress: progress, size: size); -} - -class ProgressCard_ extends State with TickerProviderStateMixin { - final String Title; - final String Values; - final String progress; - final Size size; - - ProgressCard_({ - required this.Title, - required this.Values, - required this.progress, - required this.size, - }); - - late AnimationController controller; - late double progress_; - - @override - void initState() { - progress_ = double.parse(progress.split("%").join("")) / 100; - - controller = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 800), - upperBound: progress_) - ..addListener(() { - setState(() {}); - }); - controller.forward(); - super.initState(); - } - - @override - void dispose() { - controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Card( - color: Colors.deepPurpleAccent, - child: Row( - children: [ - SizedBox(width: size.width / 55), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox(height: size.height / 28), - SizedBox( - width: size.width / 15, - height: size.height / 25, - child: AutoSizeText(Title, - style: TextStyle(fontSize: 50, color: Colors.greenAccent), - textAlign: TextAlign.center), - ), - SizedBox( - width: size.width / 15, - height: size.height / 23, - child: AutoSizeText(Values, - style: TextStyle(fontSize: 30), - textAlign: TextAlign.center), - ), - SizedBox(height: size.height / 60), - Container( - width: size.width / 12, - height: size.height / 50, - alignment: Alignment.center, - child: LinearProgressIndicator( - value: controller.value, - color: Colors.cyan, - minHeight: 18, - ), - ), - SizedBox(height: size.width / 65), - ], - ), - SizedBox(width: size.width / 55), - ], - )); - } -} - -class ProgressScreen extends StatefulWidget { - static String route = "/progress"; - @override - ProgressScreen_ createState() => ProgressScreen_(); -} diff --git a/lib/Screen/Scaffold.dart b/lib/Screen/Scaffold.dart deleted file mode 100644 index 4c2adbe..0000000 --- a/lib/Screen/Scaffold.dart +++ /dev/null @@ -1,23 +0,0 @@ -// ignore_for_file: file_names, use_key_in_widget_constructors, prefer_const_constructors - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -class RPMScaffold extends StatelessWidget { - final Widget child; - const RPMScaffold({required this.child}); - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - leading: IconButton( - icon: Icon(Icons.arrow_back), - tooltip: "返回", - onPressed: () { - Navigator.pop(context); - }, - ), - ), - body: child); - } -} diff --git a/lib/Screen/Translate.dart b/lib/Screen/Translate.dart deleted file mode 100644 index cbba338..0000000 --- a/lib/Screen/Translate.dart +++ /dev/null @@ -1,1306 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace, no_logic_in_create_state, curly_braces_in_flow_control_structures, unrelated_type_equality_checks, prefer_typing_uninitialized_variables -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; -import 'package:rpmtranslator/API/CrowdinAPI.dart'; -import 'package:rpmtranslator/API/TranslationAPI.dart'; -import 'package:rpmtranslator/API/RPMTWData.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Utility/utility.dart'; -import 'package:rpmtranslator/Widget/OkClose.dart'; -import 'package:rpmtranslator/Widget/TextHighlight.dart'; -import 'package:split_view/split_view.dart'; -import 'package:translator/translator.dart'; - -class TranslateScreen_ extends State { - final TextEditingController SearchController = TextEditingController(); - final TextEditingController TranslateTextController = TextEditingController(); - final TextEditingController CommentTextController = TextEditingController(); - final ScrollController SourceStringListController = - ScrollController(keepScrollOffset: true); - final PageController TranslatePageController = PageController(initialPage: 0); - late List SourceStringList; - final int? FileID; - final String? FileName; - int View3SelectedIndex = -1; - int SelectIndex = -1; - int StringPage = 0; - Map SelectStringInfo = {}; - late StateSetter setView3State; - late StateSetter setView2State; - late StateSetter setChangePageState; - late StateSetter setSourceStringState; - TranslateScreen_({required this.FileID, required this.FileName}); - - @override - void initState() { - super.initState(); - } - - var title_ = TextStyle( - fontSize: 20.0, - ); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - toolbarHeight: 80, - title: Column( - children: [ - Text("${FileName == null ? "" : "$FileName -"}翻譯頁面"), - FutureBuilder( - future: FileID == null - ? RPMTWData.getProgress() - : CrowdinAPI.getProgressByFile(FileID!), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - var data = FileID == null - ? double.parse(snapshot.data['progress'] - .split("%") - .join("")) / - 100 - : snapshot.data; - return Column( - children: [ - LinearProgressIndicator( - color: Colors.blue, - value: data, - ), - Text((data * 100).toStringAsFixed(2) + "%") - ], - ); - } else { - return LinearProgressIndicator(); - } - }) - ], - ), - leading: IconButton( - icon: Icon(Icons.arrow_back), - tooltip: "返回", - onPressed: () { - Navigator.pop(context); - }, - ), - centerTitle: true, - ), - body: SplitView( - children: [ - Container( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 20, - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 30, - ), - Expanded( - child: TextField( - textAlign: TextAlign.center, - controller: SearchController, - decoration: InputDecoration( - hintText: "搜尋字串...", - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.lightBlue, width: 5.0), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.lightBlue, width: 3.0), - ), - contentPadding: EdgeInsets.zero, - border: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - ), - )), - SizedBox( - width: 12, - ), - ElevatedButton( - style: new ButtonStyle( - backgroundColor: MaterialStateProperty.all( - Colors.deepPurpleAccent)), - onPressed: () { - TranslatePageController.animateToPage(0, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300)); - setState(() {}); - }, - child: Text( - "搜尋", - style: title_, - ), - ), - SizedBox( - width: 30, - ), - ], - ), - SizedBox( - height: 15, - ), - Expanded( - child: PageView.builder( - controller: TranslatePageController, - itemBuilder: (context, int Page) { - StringPage = Page; - return FutureBuilder( - future: FileID == null - ? CrowdinAPI.getAllSourceString( - SearchController.text, Page) - : CrowdinAPI.getSourceStringByFile( - FileID!, SearchController.text, Page), - builder: (context, - AsyncSnapshot?> snapshot) { - if (snapshot.hasData) { - SourceStringList = snapshot.data!; - return StatefulBuilder(builder: - (context, setSourceStringState_) { - setSourceStringState = - setSourceStringState_; - return Container( - width: - MediaQuery.of(context).size.width, - height: - MediaQuery.of(context).size.height, - child: ListView.builder( - controller: - SourceStringListController, - shrinkWrap: true, - itemCount: snapshot.data!.length, - itemBuilder: (context, int index) { - Map StringInfo = - snapshot.data![index]['data']; - String SourceString = - StringInfo['text'].toString(); - - return ListTile( - leading: FutureBuilder( - future: CrowdinAPI - .getStringTranslations( - StringInfo['id'], - ), - builder: (context, - AsyncSnapshot - snapshot) { - if (snapshot.hasData) { - if (snapshot - .data.length > - 0) { - return ColoredBox( - color: - Colors.green, - child: SizedBox( - width: 20, - height: 20, - )); - } else { - return ColoredBox( - color: Colors.red, - child: SizedBox( - width: 20, - height: 20, - )); - } - } else { - return CircularProgressIndicator(); - } - }), - title: Text(SourceString), - onTap: () { - SelectIndex = index; - SelectStringInfo = StringInfo; - setSourceStringState_(() {}); - setView2State(() {}); - View3SelectedIndex = 0; - setView3State(() {}); - }, - tileColor: SelectIndex == index - ? Colors.white12 - : Theme.of(context) - .scaffoldBackgroundColor, - ); - }), - ); - }); - } else { - return Center( - child: CircularProgressIndicator()); - } - }); - }), - ), - StatefulBuilder(builder: (context, setChangePageState_) { - setChangePageState = setChangePageState_; - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - tooltip: "上一頁", - onPressed: () async { - await TranslatePageController.animateToPage( - TranslatePageController.page!.toInt() - 1, - curve: Curves.easeOut, - duration: - const Duration(milliseconds: 300)); - setChangePageState_(() {}); - }, - icon: Icon(Icons.navigate_before)), - SizedBox( - width: 20, - ), - Text( - (StringPage + 1).toString(), - style: TextStyle(fontSize: 18), - ), - SizedBox( - width: 20, - ), - IconButton( - tooltip: "下一頁", - onPressed: () async { - if (SourceStringList.length < 20) return; - await TranslatePageController.animateToPage( - TranslatePageController.page!.toInt() + 1, - curve: Curves.easeOut, - duration: - const Duration(milliseconds: 300)); - setChangePageState_(() {}); - }, - icon: Icon(Icons.navigate_next)) - ], - ); - }) - ], - ), - ), - TranslationStringView(), - StatefulBuilder(builder: (context, setView3State_) { - setView3State = setView3State_; - return SplitView( - viewMode: SplitViewMode.Vertical, - children: [ - Container( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - child: Row(mainAxisSize: MainAxisSize.min, children: [ - Expanded( - child: ListTile( - title: AutoSizeText("討論區", - textAlign: TextAlign.center), - leading: Icon(Icons.comment), - onTap: () { - View3SelectedIndex = 0; - setView3State(() {}); - }, - tileColor: View3SelectedIndex == 0 - ? Colors.white12 - : Theme.of(context).scaffoldBackgroundColor, - ), - ), - // Expanded( - // child: ListTile( - // title: AutoSizeText("詞彙表"), - // leading: Icon( - // Icons.book, - // ), - // onTap: () { - // View3SelectedIndex = 1; - // setView3State(() {}); - // }, - // tileColor: View3SelectedIndex == 1 - // ? Colors.white12 - // : Theme.of(context).scaffoldBackgroundColor, - // ), - // ), - ]), - ), - Builder(builder: (context) { - switch (View3SelectedIndex) { - case 0: - return CommentView( - SelectStringInfo: SelectStringInfo, - CommentTextController: CommentTextController, - TranslateTextController: TranslateTextController, - setView3State: setView3State, - title_: title_); - // case 1: - // return GlossariesView(); - default: - return Container(); - } - }) - ], - controller: SplitViewController( - weights: [0.05], - limits: [WeightLimit(max: 0.05, min: 0.05)]), - gripSize: 2, - ); - }) - ], - controller: SplitViewController(weights: [ - 0.2, - 0.58 - ], limits: [ - WeightLimit(max: 0.4, min: 0.2), - WeightLimit(max: 0.7, min: 0.3) - ]), - gripSize: 3, - viewMode: SplitViewMode.Horizontal)); - } - - Builder TranslationStringView() { - return Builder(builder: (context) { - List TranslationStrings = []; - return Container( - child: StatefulBuilder(builder: (context, setView2State_) { - setView2State = setView2State_; - return SplitView( - children: [ - Container( - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - child: SingleChildScrollView( - controller: ScrollController(), - child: Builder(builder: (context) { - if (SelectStringInfo != {} && - SelectStringInfo.containsKey('text')) { - return Column( - children: [ - SizedBox( - height: 15, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - onPressed: () { - utility.OpenUrl( - "https://crowdin.com/translate/resourcepack-mod-zhtw/all/en-zhtw?filter=basic&value=0#q=${SelectStringInfo['id']}"); - }, - icon: Icon(Icons.open_in_browser), - tooltip: "在 Crowdin 網站檢視此字串", - ), - IconButton( - onPressed: () { - utility.OpenUrl( - "https://crowdin.com/project/resourcepack-mod-zhtw/activity-stream?lang=56&translation_id=${SelectStringInfo['id']}"); - }, - icon: Icon(Icons.history), - tooltip: "在 Crowdin 網站查看此字串的變更紀錄", - ), - IconButton( - onPressed: () { - Clipboard.setData(ClipboardData( - text: SelectStringInfo['text'])); - }, - icon: Icon(Icons.copy_outlined), - tooltip: "複製原文", - ), - ], - ), - SizedBox( - height: 15, - ), - AutoSizeText("原文", - style: TextStyle( - color: Colors.blue, fontSize: 20)), - RPMTextHighlight( - text: SelectStringInfo['text'] - .toString() - .replaceAll("\\n", "\n"), - words: RPMTWData.HighlightedWords, - textStyle: TextStyle( - fontSize: 20.0, - color: Colors.white, - ), - textAlign: TextAlign.justify, - ), - AutoSizeText("語系鍵", - style: TextStyle( - color: Colors.blue, fontSize: 20)), - AutoSizeText( - SelectStringInfo['context'] == null - ? "無" - : SelectStringInfo['context'] - .toString() - .split("-> ") - .join(""), - ), - SizedBox( - height: 20, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - width: 15, - ), - Expanded( - child: TextField( - keyboardType: TextInputType.multiline, - maxLines: null, - textAlign: TextAlign.center, - controller: TranslateTextController, - decoration: InputDecoration( - hintText: "譯文...", - hintStyle: TextStyle(), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.white12, width: 3.0), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.lightBlue, width: 3.0), - ), - contentPadding: - EdgeInsets.symmetric(vertical: 20.0), - border: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - ), - )), - SizedBox( - width: 15, - ), - ElevatedButton( - style: new ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - Colors.deepPurpleAccent)), - onPressed: () async { - showDialog( - barrierDismissible: false, - context: context, - builder: - (context) => - Builder(builder: (context) { - if (TranslateTextController - .text.isEmpty) { - return AlertDialog( - title: Text("新增翻譯失敗", - textAlign: - TextAlign.center), - content: Text("譯文不能是空的"), - actions: [ - TextButton( - onPressed: () { - Navigator.pop( - context); - }, - child: Text("確定")) - ], - ); - } else { - return FutureBuilder( - future: CrowdinAPI - .addTranslation( - SelectStringInfo[ - 'id'], - TranslateTextController - .text), - builder: (context, - AsyncSnapshot - snapshot) { - if (snapshot - .hasData) { - Map? data = - snapshot.data; - if (data != null && - !data.containsKey( - 'errors')) { - return AlertDialog( - title: Text( - "成功新增翻譯,感謝您的翻譯貢獻", - textAlign: - TextAlign - .center), - actions: [ - TextButton( - onPressed: - () async { - Navigator.pop( - context); - TranslateTextController.text = - ""; - if (SelectIndex == - 20) { - if (SourceStringList.length < - 20) - return; - await TranslatePageController.animateToPage( - TranslatePageController.page!.toInt() + 1, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300)); - setChangePageState( - () {}); - } else { - SelectIndex = - SelectIndex + 1; - SelectStringInfo = - SourceStringList[SelectIndex]['data']; - setSourceStringState( - () {}); - setView2State( - () {}); - View3SelectedIndex = - 0; - setView3State( - () {}); - } - }, - child: Text( - "確定")) - ], - ); - } else if (data != - null && - data.containsKey( - 'errors')) { - Map error = data[ - 'errors'] - [ - 0]['error'] - ['errors'][0]; - String - errorMessage = - error[ - 'message']; - String errorCode = - error['code']; - return AlertDialog( - title: Text( - "新增翻譯失敗", - textAlign: - TextAlign - .center), - content: Column( - mainAxisSize: - MainAxisSize - .min, - children: [ - Text( - "錯誤代碼: $errorCode"), - Text( - "錯誤訊息: ${RPMTWData.TranslateErrorMessage(errorMessage)}") - ], - ), - actions: [ - OkClose() - ], - ); - } else { - return AlertDialog( - title: Text( - "發生未知錯誤", - textAlign: - TextAlign - .center), - actions: [ - OkClose() - ], - ); - } - } else { - return Center( - child: - CircularProgressIndicator()); - } - }); - } - })); - }, - child: Text( - "提交", - style: title_, - ), - ), - SizedBox( - width: 15, - ), - ], - ), - ], - ); - } else { - return Container(); - } - }), - )), - SingleChildScrollView( - controller: ScrollController(), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text("其他翻譯", style: TextStyle(fontSize: 22)), - Container( - child: Builder(builder: (context) { - final ScrollController - StringTranslationsScrollController = - ScrollController(); - final PageController StringTranslationsPageController = - PageController(initialPage: 0); - if (SelectStringInfo != {} && - SelectStringInfo.containsKey('id')) { - return Container( - child: FutureBuilder( - future: CrowdinAPI.getStringTranslations( - SelectStringInfo['id'], - ), - builder: - (context, AsyncSnapshot snapshot) { - if (snapshot.hasData && - snapshot.data != TranslationStrings) { - TranslationStrings = snapshot.data!; - return ListView.builder( - shrinkWrap: true, - itemCount: snapshot.data!.length, - controller: - StringTranslationsScrollController, - itemBuilder: (context, index) { - Map TranslationStringInfo = - TranslationStrings[index]['data']; - String TranslationText = - TranslationStringInfo['text'] - .toString() - .replaceAll("\\n", "\n"); - Map TranslationUser = - TranslationStringInfo['user']; - bool IsMe = TranslationUser['id'] == - Account.getUserID(); - return ListTile( - leading: ClipRRect( - borderRadius: - BorderRadius.circular(50.0), - child: Image.network( - TranslationUser["avatarUrl"], - width: 50, - height: 50, - fit: BoxFit.fill, - loadingBuilder: (context, - child, loadingProgress) { - if (loadingProgress == null) - return child; - return CircularProgressIndicator( - value: loadingProgress - .expectedTotalBytes != - null - ? loadingProgress - .cumulativeBytesLoaded - .toInt() / - loadingProgress - .expectedTotalBytes! - .toInt() - : null, - ); - }, - ), - ), - title: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - TranslationText, - ), - Text( - "${TranslationUser['username']} (${TranslationUser['fullName'] ?? ""})", - style: TextStyle( - color: Colors.blue)), - Text( - RPMTWData.FormatIsoTime( - TranslationStringInfo[ - 'createdAt']), - style: TextStyle( - color: - Colors.white70)) - ], - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Votes(TranslationStringInfo, - IsMe, setView2State_), - IconButton( - onPressed: () { - Clipboard.setData( - ClipboardData( - text: - TranslationText)); - }, - icon: Icon( - Icons.copy_outlined), - tooltip: "複製譯文", - ), - Builder(builder: (context) { - if (IsMe) { - return IconButton( - onPressed: () { - showDialog( - barrierDismissible: - false, - context: context, - builder: - (context) { - return FutureBuilder( - future: CrowdinAPI - .deleteTranslation( - TranslationStringInfo[ - 'id'], - ), - builder: (context, - AsyncSnapshot - DeleteSnapshot) { - print(DeleteSnapshot - .data); - if (DeleteSnapshot - .hasData && - DeleteSnapshot.data == - true) { - setView2State( - () {}); - return AlertDialog( - title: - Text("刪除翻譯成功"), - actions: [ - OkClose() - ], - ); - } else if (DeleteSnapshot - .hasData && - DeleteSnapshot.data == - true) { - return AlertDialog( - title: - Text("刪除翻譯失敗"), - actions: [ - OkClose() - ], - ); - } else { - return Center( - child: - CircularProgressIndicator()); - } - }); - }); - }, - icon: - Icon(Icons.delete), - tooltip: "刪除翻譯", - ); - } else { - return Container(); - } - }) - ], - )); - }); - } else { - return Center( - child: CircularProgressIndicator()); - } - }), - ); - } else { - return Container(); - } - }), - ), - ], - ), - ), - Container( - child: SingleChildScrollView( - controller: ScrollController(), - child: MachineTranslation( - SelectStringInfo: SelectStringInfo))), - ], - controller: SplitViewController(weights: [0.45, 0.25, 0.30]), - viewMode: SplitViewMode.Vertical, - gripSize: 2, - gripColor: Colors.white12, - ); - }), - ); - }); - } - - Widget Votes(Map TranslationStringInfo, bool IsMe, - StateSetter setView2State_) { - return FutureBuilder( - future: CrowdinAPI.getTranslationVotes( - TranslationStringInfo['id'], SelectStringInfo['id']), - builder: (context, AsyncSnapshot TranslationVotesSnapshot) { - if (TranslationVotesSnapshot.hasData) { - List TranslationVotes = TranslationVotesSnapshot.data; - return Row(children: [ - Text(CrowdinAPI.prserVote(TranslationVotes).toString(), - style: TextStyle(fontSize: 18)), - IconButton( - icon: Icon(TranslationVotes.any((Vote) => - TranslationVotes[0]['data']['user']['id'] == - Account.getUserID()) - ? Icons.thumb_up - : Icons.thumb_up_off_alt), - tooltip: "我喜歡", - onPressed: () { - showDialog( - barrierDismissible: false, - context: context, - builder: (context) { - if (IsMe) { - return AlertDialog( - title: Text("按讚失敗"), - content: Text("您不能按讚自己的翻譯"), - actions: [OkClose()], - ); - } else { - return FutureBuilder( - future: CrowdinAPI.addVote( - TranslationStringInfo['id'], - RPMTWData.MarkUp), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData && - !snapshot.data!.containsKey('error')) { - setView2State_(() {}); - return AlertDialog( - title: Text("按讚成功"), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text("確定")) - ], - ); - } else if (snapshot.hasData && - snapshot.data!.containsKey('error')) { - return AlertDialog( - title: Text("按讚失敗"), - content: Text( - "錯誤原因: ${RPMTWData.TranslateErrorMessage(snapshot.data!['error']['message'])}"), - actions: [OkClose()], - ); - } else { - return Center( - child: CircularProgressIndicator()); - } - }); - } - }); - }, - ), - IconButton( - icon: Icon(TranslationVotes.any((Vote) => - TranslationVotes[0]['data']['user']['id'] == - Account.getUserID()) - ? Icons.thumb_down - : Icons.thumb_down_off_alt), - tooltip: "我不喜歡", - onPressed: () { - showDialog( - barrierDismissible: false, - context: context, - builder: (context) { - if (IsMe) { - return AlertDialog( - title: Text("到讚失敗"), - content: Text("您不能到讚自己的翻譯"), - actions: [OkClose()], - ); - } else { - return FutureBuilder( - future: CrowdinAPI.addVote( - TranslationStringInfo['id'], - RPMTWData.MarkDown), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData && - !snapshot.data!.containsKey('error')) { - setView2State_(() {}); - return AlertDialog( - title: Text("到讚成功"), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text("確定")) - ], - ); - } else if (snapshot.hasData && - snapshot.data!.containsKey('error')) { - return AlertDialog( - title: Text("到讚失敗"), - content: Text( - "錯誤原因: ${RPMTWData.TranslateErrorMessage(snapshot.data!['error']['message'])}"), - actions: [OkClose()], - ); - } else { - return Center( - child: CircularProgressIndicator()); - } - }); - } - }); - }, - ) - ]); - } else { - return Center(child: CircularProgressIndicator()); - } - }); - } -} - -class MachineTranslation extends StatelessWidget { - final Map SelectStringInfo; - - const MachineTranslation({ - required this.SelectStringInfo, - Key? key, - }) : super(key: key); - - static final translator = GoogleTranslator(); - - @override - Widget build(BuildContext context) { - return Builder(builder: (context) { - if (SelectStringInfo.containsKey('text')) { - return Column( - children: [ - Text("機器翻譯", style: TextStyle(fontSize: 22)), - FutureBuilder( - future: - translator.translate(SelectStringInfo['text'], to: 'zh-tw'), - builder: (context, AsyncSnapshot GoogleSnapshot) { - if (GoogleSnapshot.hasData) { - return Tooltip( - message: "複製譯文", - child: ListTile( - leading: Image.network( - 'https://www.google.com/favicon.ico'), - title: Text(GoogleSnapshot.data.text - .toString() - .replaceAll("\\n", "\n")), - subtitle: Text("由 Google 翻譯提供"), - onTap: () { - Clipboard.setData(ClipboardData( - text: GoogleSnapshot.data.text - .toString() - .replaceAll("\\n", "\n"))); - }), - ); - } else if (GoogleSnapshot.hasError) { - return Text("取得 Google 翻譯失敗,錯誤原因 ${GoogleSnapshot.error}"); - } else { - return Center(child: CircularProgressIndicator()); - } - }), - FutureBuilder( - future: TranslationAPI.TranslationWithModernMT( - SelectStringInfo['text']), - builder: (context, AsyncSnapshot ModernMTSnapshot) { - if (ModernMTSnapshot.hasData) { - return Tooltip( - message: "複製譯文", - child: ListTile( - leading: Image.network( - 'https://www.modernmt.com/assets/images/favicon/favicon.ico'), - title: Text(ModernMTSnapshot.data - .toString() - .replaceAll("\\n", "\n")), - subtitle: Text("由 ModernMT 翻譯提供"), - onTap: () { - Clipboard.setData(ClipboardData( - text: ModernMTSnapshot.data - .toString() - .replaceAll("\\n", "\n"))); - }), - ); - } else if (ModernMTSnapshot.hasError) { - return Text( - "取得 ModernMT 翻譯失敗,錯誤原因 ${ModernMTSnapshot.error}"); - } else { - return Center(child: CircularProgressIndicator()); - } - }), - ], - ); - } else { - return Container(); - } - }); - } -} - -class CommentView extends StatelessWidget { - const CommentView({ - Key? key, - required this.SelectStringInfo, - required this.CommentTextController, - required this.TranslateTextController, - required this.setView3State, - required this.title_, - }) : super(key: key); - - final Map SelectStringInfo; - final TextEditingController CommentTextController; - final TextEditingController TranslateTextController; - final StateSetter setView3State; - final TextStyle title_; - static var CommentsSnapshot; - - @override - Widget build(BuildContext context) { - return Builder(builder: (context) { - if (SelectStringInfo.containsKey('text')) { - return FutureBuilder( - future: CrowdinAPI.getCommentsByString(SelectStringInfo['id'], 0), - builder: (context, AsyncSnapshot CommentsSnapshot_) { - if (CommentsSnapshot_.hasData && - CommentsSnapshot != CommentsSnapshot_.data) { - CommentsSnapshot = CommentsSnapshot_.data; - return Container( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - child: SingleChildScrollView( - child: Column( - children: [ - ListView.builder( - itemCount: CommentsSnapshot.length, - shrinkWrap: true, - itemBuilder: (context, int Index) { - Map Comment = CommentsSnapshot[Index]['data']; - Map CommentUser = Comment['user']; - return ListTile( - leading: ClipRRect( - borderRadius: BorderRadius.circular(50.0), - child: Image.network( - CommentUser["avatarUrl"], - width: 50, - height: 50, - fit: BoxFit.fill, - loadingBuilder: - (context, child, loadingProgress) { - if (loadingProgress == null) return child; - return CircularProgressIndicator( - value: loadingProgress - .expectedTotalBytes != - null - ? loadingProgress - .cumulativeBytesLoaded - .toInt() / - loadingProgress - .expectedTotalBytes! - .toInt() - : null, - ); - }, - ), - ), - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - Comment['text'], - ), - Text( - "${CommentUser['username']} (${CommentUser['fullName'] ?? ""})", - style: TextStyle(color: Colors.blue)), - Text( - RPMTWData.FormatIsoTime( - Comment['createdAt']), - style: TextStyle(color: Colors.white70)) - ], - ), - subtitle: Comment['type'] == 'issue' - ? Comment['issueStatus'] == 'unresolved' - ? Text("未解決") - : Text("已解決") - : Container(), - tileColor: Comment['type'] == 'issue' && - Comment['issueStatus'] == 'unresolved' - ? Colors.red - : Theme.of(context).scaffoldBackgroundColor, - onTap: () {}, - ); - }), - SizedBox( - height: 30, - ), - Text("討論", style: TextStyle(fontSize: 25)), - SizedBox( - height: 15, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - width: 15, - ), - Expanded( - child: TextField( - keyboardType: TextInputType.multiline, - maxLines: null, - textAlign: TextAlign.center, - controller: CommentTextController, - decoration: InputDecoration( - hintText: "新增討論...", - hintStyle: TextStyle(), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.white12, width: 3.0), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.lightBlue, width: 3.0), - ), - contentPadding: - EdgeInsets.symmetric(vertical: 20.0), - border: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - ), - )), - SizedBox( - width: 15, - ), - ElevatedButton( - style: new ButtonStyle( - backgroundColor: MaterialStateProperty.all( - Colors.deepPurpleAccent)), - onPressed: () async { - showDialog( - barrierDismissible: false, - context: context, - builder: (context) => - Builder(builder: (context) { - if (CommentTextController - .text.isEmpty) { - return AlertDialog( - title: Text("新增討論失敗", - textAlign: TextAlign.center), - content: Text("討論內文不能是空的"), - actions: [OkClose()], - ); - } else { - return FutureBuilder( - future: CrowdinAPI.addComment( - SelectStringInfo['id'], - CommentTextController.text, - RPMTWData.Comment, - ), - builder: (context, - AsyncSnapshot - snapshot) { - if (snapshot.hasData) { - Map? data = snapshot.data; - if (data != null && - !data.containsKey( - 'errors')) { - return AlertDialog( - title: Text( - "成功新增討論,感謝您的貢獻", - textAlign: TextAlign - .center), - actions: [ - TextButton( - onPressed: () { - Navigator.pop( - context); - setView3State( - () {}); - }, - child: Text("確定")) - ], - ); - } else if (data != null && - data.containsKey( - 'errors')) { - Map error = data['errors'] - [0]['error'] - ['errors'][0]; - String errorMessage = - error['message']; - String errorCode = - error['code']; - return AlertDialog( - title: Text("新增討論失敗", - textAlign: TextAlign - .center), - content: Column( - mainAxisSize: - MainAxisSize.min, - children: [ - Text( - "錯誤代碼: $errorCode"), - Text( - "錯誤訊息: ${RPMTWData.TranslateErrorMessage(errorMessage)}") - ], - ), - actions: [OkClose()], - ); - } else { - return AlertDialog( - title: Text("發生未知錯誤", - textAlign: TextAlign - .center), - actions: [OkClose()], - ); - } - } else { - return Center( - child: - CircularProgressIndicator()); - } - }); - } - })); - }, - child: Text( - "送出", - style: title_, - ), - ), - SizedBox( - width: 15, - ), - ], - ), - ], - ), - ), - ); - } else if (CommentsSnapshot_.hasError) { - return Text("取得討論失敗,錯誤原因 ${CommentsSnapshot_.error}"); - } else { - return Center(child: CircularProgressIndicator()); - } - }); - } else { - return Container(); - } - }); - } -} - -class TranslateScreen extends StatefulWidget { - final int? FileID; - final String? FileName; - const TranslateScreen({required this.FileID, required this.FileName}); - - @override - TranslateScreen_ createState() => - TranslateScreen_(FileID: FileID, FileName: FileName); -} diff --git a/lib/Screen/UnknownScreen.dart b/lib/Screen/UnknownScreen.dart deleted file mode 100644 index 7d62baa..0000000 --- a/lib/Screen/UnknownScreen.dart +++ /dev/null @@ -1,15 +0,0 @@ -// ignore_for_file: file_names, use_key_in_widget_constructors, prefer_const_constructors - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import 'Scaffold.dart'; - -class UnknownScreen extends StatelessWidget { - @override - Widget build(BuildContext context) { - return RPMScaffold( - child: Center( - child: Text('404 找不到此頁面!', style: TextStyle(fontSize: 100)))); - } -} diff --git a/lib/Screen/UploadTranslation.dart b/lib/Screen/UploadTranslation.dart deleted file mode 100644 index 736cbdf..0000000 --- a/lib/Screen/UploadTranslation.dart +++ /dev/null @@ -1,97 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace, no_logic_in_create_state - -import 'package:universal_io/io.dart'; - -import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:path/path.dart' as path; -import 'package:rpmtranslator/API/CrowdinAPI.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Widget/OkClose.dart'; - -class UploadTranslation extends StatefulWidget { - final int FileID; - final String FileName; - const UploadTranslation({ - required this.FileID, - required this.FileName, - Key? key, - }) : super(key: key); - - @override - State createState() => - _UploadTranslationState(FileID: FileID, FileName: FileName); -} - -class _UploadTranslationState extends State { - final int FileID; - final String FileName; - _UploadTranslationState({ - required this.FileID, - required this.FileName, - }); - - @override - Widget build(BuildContext context) { - return AlertDialog( - title: Text("上傳翻譯"), - content: Text("請選擇要上傳的檔案"), - actions: [ - TextButton( - onPressed: () async { - final XFile? file = await FileSelectorPlatform.instance - .openFile(acceptedTypeGroups: [ - XTypeGroup( - label: "翻譯檔案", extensions: [path.extension(FileName)]) - ]); - if (file != null) { - Navigator.pop(context); - showDialog( - barrierDismissible: false, - context: context, - builder: (context) { - return FutureBuilder( - future: CrowdinAPI.updateTranslation( - file, FileID, FileName), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - if (snapshot.data == true) { - return AlertDialog( - title: Text("上傳成功"), - actions: [OkClose()], - ); - } else { - return AlertDialog( - title: Text("上傳失敗"), - actions: [OkClose()], - ); - } - } else { - return AlertDialog( - title: Text("上傳檔案至 Crowdin 伺服器中..."), - content: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - height: 20, - ), - CircularProgressIndicator(), - SizedBox( - height: 20, - ) - ], - ), - ); - } - }); - }); - } else { - return; - } - }, - child: Text("選擇檔案")) - ]); - } -} diff --git a/lib/Utility/utility.dart b/lib/Utility/utility.dart deleted file mode 100644 index e495a06..0000000 --- a/lib/Utility/utility.dart +++ /dev/null @@ -1,26 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, prefer_const_literals_to_create_immutables, camel_case_types - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:rpmtranslator/Screen/AccountWeb.dart'; -import 'package:rpmtranslator/Screen/CrowdinOauth.dart'; -import 'package:url_launcher/url_launcher.dart'; - -class utility { - static Future OpenUrl(String url) async { - if (await canLaunch(url)) { - launch(url); - } else { - print("Can't open the url $url"); - } - } - - static void IsWebAccount(BuildContext context) { - if (kIsWeb) { - showDialog(context: context, builder: (context) => AccountWebScreen()); - } else { - showDialog(context: context, builder: (context) => CrowdinAuthScreen()); - } - } -} diff --git a/lib/Widget/AccountNone.dart b/lib/Widget/AccountNone.dart deleted file mode 100644 index fe84127..0000000 --- a/lib/Widget/AccountNone.dart +++ /dev/null @@ -1,71 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Account/CrowdinAuth.dart'; -import 'package:rpmtranslator/Utility/utility.dart'; -import 'package:rpmtranslator/Widget/OkClose.dart'; - -class AccountNone extends StatelessWidget { - const AccountNone({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - if (Account.has() && Account.expired()) { - return FutureBuilder( - future: CrowdinAuthHandler.RefreshToken(Account.getRefreshToken()), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - if (snapshot.data == true) { - return AlertDialog( - title: Text("提示訊息"), - content: Text("更新登入憑證成功"), - actions: [OkClose()], - ); - } else { - return AlertDialog( - title: Text("錯誤訊息"), - content: Text("更新登入憑證失敗,請手動重新登入"), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - utility.IsWebAccount(context); - }, - child: Text("確定")) - ], - ); - } - } else { - return AlertDialog( - title: Text("錯誤訊息"), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text("偵測到您的 Crowdin 登入憑證已過期,正在嘗試更新登入憑證..."), - SizedBox(height: 12), - CircularProgressIndicator() - ], - ), - ); - } - }); - } else { - return AlertDialog( - title: Text("提示訊息"), - content: Text("請先登入帳號再執行此步驟"), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - utility.IsWebAccount(context); - }, - child: Text("確定")) - ], - ); - } - } -} diff --git a/lib/Widget/HighlightedWord.dart b/lib/Widget/HighlightedWord.dart deleted file mode 100644 index e8f057f..0000000 --- a/lib/Widget/HighlightedWord.dart +++ /dev/null @@ -1,24 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace, overridden_fields - -import 'package:flutter/cupertino.dart'; -import 'package:highlight_text/highlight_text.dart'; - -class RPMHighlightedWord extends HighlightedWord { - final TextStyle textStyle; - final VoidCallback onTap; - final BoxDecoration? decoration; - final EdgeInsetsGeometry? padding; - final String? tooltip; - - RPMHighlightedWord( - {required this.onTap, - required this.textStyle, - this.decoration, - this.padding, - this.tooltip}) - : super( - onTap: onTap, - textStyle: textStyle, - decoration: decoration, - padding: padding); -} diff --git a/lib/Widget/OkClose.dart b/lib/Widget/OkClose.dart deleted file mode 100644 index 72cf0b7..0000000 --- a/lib/Widget/OkClose.dart +++ /dev/null @@ -1,19 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -class OkClose extends StatelessWidget { - const OkClose({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text("確定")); - } -} diff --git a/lib/Widget/TextHighlight.dart b/lib/Widget/TextHighlight.dart deleted file mode 100644 index d98b821..0000000 --- a/lib/Widget/TextHighlight.dart +++ /dev/null @@ -1,133 +0,0 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, unnecessary_new, camel_case_types, annotate_overrides, prefer_const_literals_to_create_immutables, prefer_equal_for_default_values, unused_element, avoid_unnecessary_containers, use_key_in_widget_constructors, sized_box_for_whitespace, overridden_fields - -import 'dart:collection'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:highlight_text/highlight_text.dart'; - -import 'HighlightedWord.dart'; - -class RPMTextHighlight extends TextHighlight { - final String text; - final LinkedHashMap words; - final TextStyle textStyle; - final TextAlign textAlign; - final TextDirection? textDirection; - final bool softWrap; - final TextOverflow overflow; - final double textScaleFactor; - final int? maxLines; - final Locale? locale; - final StrutStyle? strutStyle; - final bool enableCaseSensitive; - - RPMTextHighlight({ - required this.text, - required this.words, - this.textStyle = const TextStyle( - fontSize: 25.0, - color: Colors.white, - ), - this.textAlign = TextAlign.start, - this.textDirection, - this.softWrap = true, - this.overflow = TextOverflow.clip, - this.textScaleFactor = 1.0, - this.maxLines, - this.locale, - this.strutStyle, - this.enableCaseSensitive = false, - }) : super( - text: text, - words: words, - textStyle: textStyle, - textAlign: textAlign, - textDirection: textDirection, - softWrap: softWrap, - overflow: overflow, - textScaleFactor: textScaleFactor, - maxLines: maxLines, - locale: locale, - strutStyle: strutStyle); - - @override - Widget build(BuildContext context) { - List _textWords = _bind(); - - return RichText( - text: _buildSpan(_textWords), - locale: locale, - maxLines: maxLines, - overflow: overflow, - softWrap: softWrap, - strutStyle: strutStyle, - textAlign: textAlign, - textDirection: textDirection, - textScaleFactor: textScaleFactor, - ); - } - - List _bind() { - String bindedText = text; - for (String word in words.keys) { - if (enableCaseSensitive) { - bindedText = bindedText.replaceAll( - word, '${words.keys.toList().indexOf(word)}'); - } else { - int strIndex = bindedText.toLowerCase().indexOf(word.toLowerCase()); - if (strIndex > 0) { - bindedText = bindedText.replaceRange(strIndex, strIndex + word.length, - '${words.keys.toList().indexOf(word)}'); - } - } - } - - List splitedTexts = bindedText.split(""); - splitedTexts.removeWhere((s) => s.isEmpty); - - return splitedTexts; - } - - TextSpan _buildSpan(List bindedWords) { - if (bindedWords.isEmpty) return TextSpan(); - - String nextToDisplay = bindedWords.first; - bindedWords.removeAt(0); - - int? index = int.tryParse(nextToDisplay); - - if (index != null) { - String currentWord = words.keys.toList()[index]; - return TextSpan( - children: [ - WidgetSpan( - child: Tooltip( - message: words[currentWord]!.tooltip ?? "", - child: GestureDetector( - onTap: words[currentWord]!.onTap, - child: Container( - padding: words[currentWord]!.padding, - decoration: words[currentWord]!.decoration, - child: Text( - currentWord, - style: words[currentWord]!.textStyle, - ), - ), - ), - ), - ), - _buildSpan(bindedWords), - ], - ); - } - - return TextSpan( - text: nextToDisplay, - style: textStyle, - children: [ - _buildSpan(bindedWords), - ], - ); - } -} diff --git a/lib/main.dart b/lib/main.dart index c3af6c7..7af2770 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,141 +1,44 @@ -// ignore_for_file: non_constant_identifier_names, unused_local_variable, file_names, avoid_print, prefer_const_constructors, prefer_const_literals_to_create_immutables -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:rpmtranslator/API/APIs.dart'; -import 'package:rpmtranslator/Account/Account.dart'; -import 'package:rpmtranslator/Screen/Contribution.dart'; -import 'package:rpmtranslator/Widget/AccountNone.dart'; -import 'package:rpmtranslator/Widget/OkClose.dart'; -import 'package:url_strategy/url_strategy.dart'; -import 'Screen/Files.dart'; -import 'Screen/Progress.dart'; -import 'Screen/Mods.dart'; -import 'Screen/Scaffold.dart'; -import 'Screen/Translate.dart'; -import 'Screen/UnknownScreen.dart'; -import 'Utility/utility.dart'; - -extension BoolParsing on String { - bool parseBool() { - return toLowerCase() == 'true'; - } -} +import 'package:flutter_svg/svg.dart'; void main() { - setPathUrlStrategy(); - runApp(const App()); + runApp(const TranslatorApp()); } -class App extends StatelessWidget { - const App({Key? key}) : super(key: key); +class TranslatorApp extends StatelessWidget { + const TranslatorApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( - title: 'RPMTranslator - RPMTW 模組專屬翻譯器', - theme: ThemeData(brightness: Brightness.dark, fontFamily: 'font'), - debugShowCheckedModeBanner: false, - initialRoute: HomePage.route, - onGenerateRoute: (settings) { - if (settings.name == HomePage.route || settings.name == '/index.html') { + title: 'RPMTranslator', + theme: ThemeData( + brightness: Brightness.dark, + fontFamily: 'font', + useMaterial3: true), + debugShowCheckedModeBanner: false, + initialRoute: HomePage.route, + onGenerateRoute: (settings) { return MaterialPageRoute( - settings: settings, builder: (context) => HomePage()); - } - - // '?auth-code=${AuthCode}' - var uri = Uri.parse(settings.name!); - if (uri.queryParameters.containsKey('auth-code')) { - var AuthCode = uri.queryParameters['auth-code']; - if (AuthCode == "error") { - return MaterialPageRoute( - settings: settings, - builder: (context) => RPMScaffold( - child: AlertDialog( - title: Text("提示資訊"), - content: - Text("登入帳號失敗,請嘗試重新登入,如果仍然失敗,請前往我們的 Discord 伺服器詢問"), - actions: [ - IconButton( - icon: Icon(Icons.manage_accounts), - onPressed: () { - utility.IsWebAccount(context); - }, - tooltip: "重新登入帳號", - ), - ], - ), - )); - } else if (AuthCode == "success") { - return MaterialPageRoute( - settings: settings, - builder: (context) => RPMScaffold( - child: AlertDialog( - title: Text("提示資訊"), - content: Text("登入帳號成功"), - actions: [OkClose()], - ), - )); - } - } - // "/mods" url - if (settings.name!.startsWith(ModsScreen.route)) { - if (settings.name == ModsScreen.route) { - return MaterialPageRoute( - settings: settings, builder: (context) => ModsScreen()); - } else if (uri.pathSegments.length == 3) { - // "/mods/${CrowdinDirID}/files" - int CrowdinDirID = int.parse(uri.pathSegments[1]); - return MaterialPageRoute( - settings: settings, - builder: (context) => FilesScreen(DirID: CrowdinDirID)); - } else if (uri.pathSegments.length == 5) { - // "/mods/${CrowdinDirID}/files/${CrowdinFileID}/translate?FileName=${FileName}" - String? FileName = uri.queryParameters['FileName']; - int CrowdinFileID = int.parse(uri.pathSegments[3]); - return MaterialPageRoute( - settings: settings, - builder: (context) => - TranslateScreen(FileID: CrowdinFileID, FileName: FileName)); - } - } - - if (settings.name == ProgressScreen.route) { - return MaterialPageRoute( - settings: settings, builder: (context) => ProgressScreen()); - } - - if (settings.name == ContributionScreen.route) { - return MaterialPageRoute( - settings: settings, builder: (context) => ContributionScreen()); - } - - return MaterialPageRoute( - settings: settings, builder: (context) => UnknownScreen()); - }, - ); + settings: settings, + builder: (context) => const HomePage(), + ); + }); } } class HomePage extends StatefulWidget { static String route = "/"; const HomePage({Key? key}) : super(key: key); + @override State createState() => _HomePageState(); } class _HomePageState extends State { + int _selectedIndex = 0; + @override void initState() { - if (!kIsWeb) { - //如果不是網站才使用檔案儲存 - if (!Account.AccountFile.existsSync()) { - //如果不存在帳號檔案就建立一個 - Account.AccountFile - ..createSync(recursive: true) - ..writeAsStringSync(json.encode({})); - } - } super.initState(); } @@ -143,116 +46,40 @@ class _HomePageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - leading: IconButton( - icon: Icon(Icons.home), - onPressed: () async { - await utility.OpenUrl(HomePageUrl); - }, - tooltip: "官方網站"), - title: Center( - child: Text("RPMTranslator - RPMTW 模組專屬翻譯器"), - ), - centerTitle: true, - actions: [ - IconButton( - icon: Icon(Icons.manage_accounts), - onPressed: () { - utility.IsWebAccount(context); + leadingWidth: 48, + leading: SvgPicture.asset("assets/images/logo.svg"), + titleSpacing: 0, + title: const Text("RPMTranslator")), + body: Row( + children: [ + NavigationRail( + selectedIndex: _selectedIndex, + onDestinationSelected: (int index) { + setState(() { + _selectedIndex = index; + }); }, - tooltip: "登入帳號", - ), - ]), - body: Center( - child: Transform.scale( - scale: 2.5, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - TextButton( - onPressed: () { - Navigator.pushNamed(context, ProgressScreen.route); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.donut_large, - color: Colors.blue, - ), - SizedBox( - width: 5, - ), - Text( - "查看翻譯進度", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 25), - ) - ], + labelType: NavigationRailLabelType.all, + destinations: const [ + NavigationRailDestination( + icon: Icon(Icons.home), + label: Text('HOME'), + ), + NavigationRailDestination( + icon: Icon(Icons.translate), + label: Text('Translate'), ), - ), - SizedBox( - height: MediaQuery.of(context).size.width / 130, - ), - TextButton( - onPressed: () { - if (Account.has() && !Account.expired()) { - Navigator.pushNamed(context, ModsScreen.route); - } else { - showDialog( - context: context, - builder: (context) { - return AccountNone(); - }); - } - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.translate, - color: Colors.blue, - ), - SizedBox( - width: 5, - ), - Text("翻譯模組", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 25)) - ], + NavigationRailDestination( + icon: Icon(Icons.article), + label: Text('Report'), ), - ), - SizedBox( - height: MediaQuery.of(context).size.width / 130, - ), - TextButton( - onPressed: () { - Navigator.pushNamed(context, ContributionScreen.route); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.people, - color: Colors.blue, - ), - SizedBox( - width: 5, - ), - Text( - "查看翻譯貢獻者", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 25), - ) - ], + NavigationRailDestination( + icon: Icon(Icons.info), + label: Text('About'), ), - ), - ], - ), - ), + ]), + const Text("test"), + ], ), ); } diff --git a/lib/path.dart b/lib/path.dart deleted file mode 100644 index ba19860..0000000 --- a/lib/path.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:universal_io/io.dart'; -import 'package:path/path.dart'; - -late var home; - -_getData() { - Map envVars = Platform.environment; - if (Platform.isLinux) { - home = envVars['HOME']; - return join(home, ".local", "share"); - } else if (Platform.isMacOS) { - home = envVars['HOME']; - } else if (Platform.isWindows) { - home = envVars['UserProfile']; - return join(home, "AppData", "Roaming"); - } else { - home = envVars['UserProfile']; - return join(home); - } -} - -_getConfig() { - Map envVars = Platform.environment; - if (Platform.isLinux) { - home = envVars['HOME']; - return join(home, ".config"); - } else if (Platform.isMacOS) { - home = envVars['HOME']; - } else if (Platform.isWindows) { - home = envVars['UserProfile']; - return join(home, "AppData", "Local"); - } else { - home = envVars['UserProfile']; - return join(home); - } -} - -var dataHome = Directory(join(_getData(), "RPMTranslator")); -var configHome = Directory(join(_getConfig(), "RPMTranslator")); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 7299b5c..f6f23bf 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,13 +6,9 @@ #include "generated_plugin_registrant.h" -#include #include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); - file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 627fdc7..f16b4c3 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,10 +3,12 @@ # list(APPEND FLUTTER_PLUGIN_LIST - file_selector_linux url_launcher_linux ) +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) @@ -15,3 +17,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 4e44bc8..8236f57 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,8 @@ import FlutterMacOS import Foundation -import file_selector_macos import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.yaml b/pubspec.yaml index 4c63476..bc45829 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,45 +1,41 @@ name: rpmtranslator -description: RPMTW 專屬模組翻譯器 +description: RPMTW Translator -publish_to: 'none' +publish_to: "none" -version: 1.0.0+1 +version: 1.0.0 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.15.0 <3.0.0" + flutter: ">=2.10.0" dependencies: flutter: sdk: flutter - - cupertino_icons: ^1.0.2 - flutter_lints: ^1.0.0 - http: - url_launcher: - path: - io: + cupertino_icons: ^1.0.4 + url_launcher: ^6.0.20 + path: ^1.8.1 auto_size_text: 3.0.0-nullsafety.0 split_view: oauth2: - translator: ^0.1.7 html: ^0.15.0 - file_selector_platform_interface: ^2.0.0 - file_selector_linux: - file_selector_macos: - file_selector_windows: - file_selector: highlight_text: ^1.1.0 universal_io: ^2.0.4 universal_html: ^2.0.8 url_strategy: ^0.2.0 + flutter_svg: ^1.0.3 + rpmtw_api_client_flutter: ^1.0.8-dev.0 dev_dependencies: flutter_test: sdk: flutter - + flutter_lints: ^1.0.0 + flutter: uses-material-design: true + assets: + - assets/images/ fonts: - - family: font - fonts: - - asset: fonts/NotoSansCJKtc-Regular.otf #Source: https://www.google.com/get/noto/ \ No newline at end of file + - family: font + fonts: + - asset: assets/fonts/NotoSansCJKtc-Regular.otf #Source: https://www.google.com/get/noto/ diff --git a/web/404.html b/web/404.html index f678767..7d62512 100644 --- a/web/404.html +++ b/web/404.html @@ -15,10 +15,13 @@ This is a placeholder for base href that will be replaced by the value of the `--base-href` argument provided to `flutter build`. --> - + + - + + @@ -26,126 +29,190 @@ + + + RPMTranslator + + + - - - -
-
+
+ +
+
+
+
+
+
+
- - - - - + }); + + // If service worker doesn't succeed in a reasonable amount of time, + // fallback to plain + \ No newline at end of file diff --git a/web/favicon.png b/web/favicon.png index 8aaa46a..df68ffb 100644 Binary files a/web/favicon.png and b/web/favicon.png differ diff --git a/web/index.html b/web/index.html index f3c8e21..7d62512 100644 --- a/web/index.html +++ b/web/index.html @@ -16,9 +16,12 @@ the `--base-href` argument provided to `flutter build`. --> + - + + @@ -26,126 +29,190 @@ + + + RPMTranslator + + + - - - -
-
+
+ +
+
+
+
+
+
+
- - - - - + }); + + // If service worker doesn't succeed in a reasonable amount of time, + // fallback to plain + \ No newline at end of file diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index af9ae5d..4f78848 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,12 +6,9 @@ #include "generated_plugin_registrant.h" -#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { - FileSelectorPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FileSelectorPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b944b21..88b22e5 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,10 +3,12 @@ # list(APPEND FLUTTER_PLUGIN_LIST - file_selector_windows url_launcher_windows ) +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) @@ -15,3 +17,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/winuwp/.gitignore b/winuwp/.gitignore deleted file mode 100644 index d492d0d..0000000 --- a/winuwp/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/winuwp/CMakeLists.txt b/winuwp/CMakeLists.txt deleted file mode 100644 index 13282d1..0000000 --- a/winuwp/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -cmake_minimum_required(VERSION 3.8) -set(CMAKE_SYSTEM_NAME WindowsStore) -set(CMAKE_SYSTEM_VERSION 10.0) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED YES) - -project(runner LANGUAGES CXX) - -cmake_policy(SET CMP0079 NEW) - -set(BINARY_NAME "app") - -# Configure build options. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() - -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100" /await) - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") - target_compile_definitions(${TARGET} PRIVATE WINUWP) - set_target_properties(${TARGET} PROPERTIES VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION 10.0.18362.0) -endfunction() - -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") - -# Flutter library and tool build rules. -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build -add_subdirectory("runner_uwp") - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) diff --git a/winuwp/flutter/CMakeLists.txt b/winuwp/flutter/CMakeLists.txt deleted file mode 100644 index ddf4525..0000000 --- a/winuwp/flutter/CMakeLists.txt +++ /dev/null @@ -1,91 +0,0 @@ -cmake_minimum_required(VERSION 3.8) -set(CMAKE_SYSTEM_NAME WindowsStore) -set(CMAKE_SYSTEM_VERSION 10.0) -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -include(CMakePrintHelpers) - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows_winuwp.dll") - -# === Assets === -set(CMAKE_INSTALL_MANIFEST "${EPHEMERAL_DIR}/install_manifest") -file(STRINGS ${CMAKE_INSTALL_MANIFEST} INSTALL_MANIFEST_CONTENT) - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(INSTALL_MANIFEST_CONTENT ${INSTALL_MANIFEST_CONTENT} PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) diff --git a/winuwp/flutter/generated_plugin_registrant.cc b/winuwp/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 8b6d468..0000000 --- a/winuwp/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,11 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - - -void RegisterPlugins(flutter::PluginRegistry* registry) { -} diff --git a/winuwp/flutter/generated_plugin_registrant.h b/winuwp/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d8..0000000 --- a/winuwp/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/winuwp/flutter/generated_plugins.cmake b/winuwp/flutter/generated_plugins.cmake deleted file mode 100644 index 4d10c25..0000000 --- a/winuwp/flutter/generated_plugins.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) diff --git a/winuwp/project_version b/winuwp/project_version deleted file mode 100644 index c227083..0000000 --- a/winuwp/project_version +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-100.png b/winuwp/runner_uwp/Assets/LargeTile.scale-100.png deleted file mode 100644 index fa651eb..0000000 Binary files a/winuwp/runner_uwp/Assets/LargeTile.scale-100.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-125.png b/winuwp/runner_uwp/Assets/LargeTile.scale-125.png deleted file mode 100644 index 649e076..0000000 Binary files a/winuwp/runner_uwp/Assets/LargeTile.scale-125.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-150.png b/winuwp/runner_uwp/Assets/LargeTile.scale-150.png deleted file mode 100644 index fd14c60..0000000 Binary files a/winuwp/runner_uwp/Assets/LargeTile.scale-150.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-200.png b/winuwp/runner_uwp/Assets/LargeTile.scale-200.png deleted file mode 100644 index 873537f..0000000 Binary files a/winuwp/runner_uwp/Assets/LargeTile.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/LargeTile.scale-400.png b/winuwp/runner_uwp/Assets/LargeTile.scale-400.png deleted file mode 100644 index 979878f..0000000 Binary files a/winuwp/runner_uwp/Assets/LargeTile.scale-400.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/LockScreenLogo.scale-200.png b/winuwp/runner_uwp/Assets/LockScreenLogo.scale-200.png deleted file mode 100644 index 735f57a..0000000 Binary files a/winuwp/runner_uwp/Assets/LockScreenLogo.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-100.png b/winuwp/runner_uwp/Assets/SmallTile.scale-100.png deleted file mode 100644 index 35e7f62..0000000 Binary files a/winuwp/runner_uwp/Assets/SmallTile.scale-100.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-125.png b/winuwp/runner_uwp/Assets/SmallTile.scale-125.png deleted file mode 100644 index 2a74cc6..0000000 Binary files a/winuwp/runner_uwp/Assets/SmallTile.scale-125.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-150.png b/winuwp/runner_uwp/Assets/SmallTile.scale-150.png deleted file mode 100644 index 1571248..0000000 Binary files a/winuwp/runner_uwp/Assets/SmallTile.scale-150.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-200.png b/winuwp/runner_uwp/Assets/SmallTile.scale-200.png deleted file mode 100644 index 07ec2dd..0000000 Binary files a/winuwp/runner_uwp/Assets/SmallTile.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SmallTile.scale-400.png b/winuwp/runner_uwp/Assets/SmallTile.scale-400.png deleted file mode 100644 index c205729..0000000 Binary files a/winuwp/runner_uwp/Assets/SmallTile.scale-400.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-100.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-100.png deleted file mode 100644 index 6012579..0000000 Binary files a/winuwp/runner_uwp/Assets/SplashScreen.scale-100.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-125.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-125.png deleted file mode 100644 index 0c35be8..0000000 Binary files a/winuwp/runner_uwp/Assets/SplashScreen.scale-125.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-150.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-150.png deleted file mode 100644 index f1e60f3..0000000 Binary files a/winuwp/runner_uwp/Assets/SplashScreen.scale-150.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-200.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-200.png deleted file mode 100644 index 73d2461..0000000 Binary files a/winuwp/runner_uwp/Assets/SplashScreen.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/SplashScreen.scale-400.png b/winuwp/runner_uwp/Assets/SplashScreen.scale-400.png deleted file mode 100644 index b2b7ca9..0000000 Binary files a/winuwp/runner_uwp/Assets/SplashScreen.scale-400.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-100.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-100.png deleted file mode 100644 index cdc3e97..0000000 Binary files a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-100.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-125.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-125.png deleted file mode 100644 index 71e5a11..0000000 Binary files a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-125.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-150.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-150.png deleted file mode 100644 index 60f2e18..0000000 Binary files a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-150.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-200.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-200.png deleted file mode 100644 index 2081408..0000000 Binary files a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-400.png b/winuwp/runner_uwp/Assets/Square150x150Logo.scale-400.png deleted file mode 100644 index 605aacb..0000000 Binary files a/winuwp/runner_uwp/Assets/Square150x150Logo.scale-400.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png deleted file mode 100644 index 1c78d96..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png deleted file mode 100644 index d49d3d8..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png deleted file mode 100644 index 8896224..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png b/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png deleted file mode 100644 index 6389ede..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-100.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-100.png deleted file mode 100644 index 47e3cd2..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-100.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-125.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-125.png deleted file mode 100644 index 50faa93..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-125.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-150.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-150.png deleted file mode 100644 index f0293ed..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-150.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-200.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-200.png deleted file mode 100644 index e54a56d..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-400.png b/winuwp/runner_uwp/Assets/Square44x44Logo.scale-400.png deleted file mode 100644 index 4b5fb17..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.scale-400.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-16.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-16.png deleted file mode 100644 index a1a6ec7..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-16.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24.png deleted file mode 100644 index c67a8e1..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png deleted file mode 100644 index 47d36f6..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-256.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-256.png deleted file mode 100644 index 50efc00..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-256.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-32.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-32.png deleted file mode 100644 index f86682c..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-32.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-48.png b/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-48.png deleted file mode 100644 index 7561269..0000000 Binary files a/winuwp/runner_uwp/Assets/Square44x44Logo.targetsize-48.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.png b/winuwp/runner_uwp/Assets/StoreLogo.png deleted file mode 100644 index 7385b56..0000000 Binary files a/winuwp/runner_uwp/Assets/StoreLogo.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-100.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-100.png deleted file mode 100644 index fcefe81..0000000 Binary files a/winuwp/runner_uwp/Assets/StoreLogo.scale-100.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-125.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-125.png deleted file mode 100644 index 4381be7..0000000 Binary files a/winuwp/runner_uwp/Assets/StoreLogo.scale-125.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-150.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-150.png deleted file mode 100644 index e49390b..0000000 Binary files a/winuwp/runner_uwp/Assets/StoreLogo.scale-150.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-200.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-200.png deleted file mode 100644 index fb740e8..0000000 Binary files a/winuwp/runner_uwp/Assets/StoreLogo.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/StoreLogo.scale-400.png b/winuwp/runner_uwp/Assets/StoreLogo.scale-400.png deleted file mode 100644 index d147274..0000000 Binary files a/winuwp/runner_uwp/Assets/StoreLogo.scale-400.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/Wide310x150Logo.scale-200.png b/winuwp/runner_uwp/Assets/Wide310x150Logo.scale-200.png deleted file mode 100644 index 288995b..0000000 Binary files a/winuwp/runner_uwp/Assets/Wide310x150Logo.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-100.png b/winuwp/runner_uwp/Assets/WideTile.scale-100.png deleted file mode 100644 index 1cb688c..0000000 Binary files a/winuwp/runner_uwp/Assets/WideTile.scale-100.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-125.png b/winuwp/runner_uwp/Assets/WideTile.scale-125.png deleted file mode 100644 index 7292396..0000000 Binary files a/winuwp/runner_uwp/Assets/WideTile.scale-125.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-150.png b/winuwp/runner_uwp/Assets/WideTile.scale-150.png deleted file mode 100644 index d4b275a..0000000 Binary files a/winuwp/runner_uwp/Assets/WideTile.scale-150.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-200.png b/winuwp/runner_uwp/Assets/WideTile.scale-200.png deleted file mode 100644 index 6012579..0000000 Binary files a/winuwp/runner_uwp/Assets/WideTile.scale-200.png and /dev/null differ diff --git a/winuwp/runner_uwp/Assets/WideTile.scale-400.png b/winuwp/runner_uwp/Assets/WideTile.scale-400.png deleted file mode 100644 index 73d2461..0000000 Binary files a/winuwp/runner_uwp/Assets/WideTile.scale-400.png and /dev/null differ diff --git a/winuwp/runner_uwp/CMakeLists.txt b/winuwp/runner_uwp/CMakeLists.txt deleted file mode 100644 index ee7c2d9..0000000 --- a/winuwp/runner_uwp/CMakeLists.txt +++ /dev/null @@ -1,127 +0,0 @@ -cmake_minimum_required (VERSION 3.8) -set(CMAKE_SYSTEM_NAME WindowsStore) -set(CMAKE_SYSTEM_VERSION 10.0) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED YES) - -include(CMakePrintHelpers) - -project (runner LANGUAGES CXX) - -# UWP tile and icon assets. -set(ASSET_FILES ${ASSET_FILES} - Assets/LargeTile.scale-100.png - Assets/LargeTile.scale-125.png - Assets/LargeTile.scale-150.png - Assets/LargeTile.scale-200.png - Assets/LargeTile.scale-400.png - Assets/LockScreenLogo.scale-200.png - Assets/SmallTile.scale-100.png - Assets/SmallTile.scale-125.png - Assets/SmallTile.scale-150.png - Assets/SmallTile.scale-200.png - Assets/SmallTile.scale-400.png - Assets/SplashScreen.scale-100.png - Assets/SplashScreen.scale-125.png - Assets/SplashScreen.scale-150.png - Assets/SplashScreen.scale-200.png - Assets/SplashScreen.scale-400.png - Assets/Square44x44Logo.altform-unplated_targetsize-16.png - Assets/Square44x44Logo.altform-unplated_targetsize-32.png - Assets/Square44x44Logo.altform-unplated_targetsize-48.png - Assets/Square44x44Logo.altform-unplated_targetsize-256.png - Assets/Square44x44Logo.scale-100.png - Assets/Square44x44Logo.scale-125.png - Assets/Square44x44Logo.scale-150.png - Assets/Square44x44Logo.scale-200.png - Assets/Square44x44Logo.scale-400.png - Assets/Square44x44Logo.targetsize-16.png - Assets/Square44x44Logo.targetsize-24.png - Assets/Square44x44Logo.targetsize-24_altform-unplated.png - Assets/Square44x44Logo.targetsize-32.png - Assets/Square44x44Logo.targetsize-48.png - Assets/Square44x44Logo.targetsize-256.png - Assets/Square150x150Logo.scale-100.png - Assets/Square150x150Logo.scale-125.png - Assets/Square150x150Logo.scale-150.png - Assets/Square150x150Logo.scale-200.png - Assets/Square150x150Logo.scale-400.png - Assets/StoreLogo.png - Assets/StoreLogo.scale-100.png - Assets/StoreLogo.scale-125.png - Assets/StoreLogo.scale-150.png - Assets/StoreLogo.scale-200.png - Assets/StoreLogo.scale-400.png - Assets/Wide310x150Logo.scale-200.png - Assets/WideTile.scale-100.png - Assets/WideTile.scale-125.png - Assets/WideTile.scale-150.png - Assets/WideTile.scale-200.png - Assets/WideTile.scale-400.png -) - -# Configure package manifest file. -set(APP_MANIFEST_NAME Package.appxmanifest) -set(APP_MANIFEST_TARGET_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME}) -set(SHORT_NAME ${BINARY_NAME}) -set(PACKAGE_GUID "F72C7595-B393-4281-896D-88F8D4E53014") - -configure_file( - appxmanifest.in - ${APP_MANIFEST_TARGET_LOCATION} - @ONLY) - -set(CONTENT_FILES ${APP_MANIFEST_TARGET_LOCATION}) - -# Configure package content files. -set_property(SOURCE ${CONTENT_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) - -set(RESOURCE_FILES ${ASSET_FILES} ${CONTENT_FILES} Windows_TemporaryKey.pfx) -set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) -set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_LOCATION "Assets") - -set(STRING_FILES Resources.pri) -set_property(SOURCE ${STRING_FILES} PROPERTY VS_TOOL_OVERRIDE "PRIResource") - -source_group("Resource Files" FILES ${RESOURCE_FILES} ${CONTENT_FILES} ${STRING_FILES}) - -# Configure Flutter assets using tool generated install manifest -foreach(ITEM ${INSTALL_MANIFEST_CONTENT}) - get_filename_component(ITEM_REL ${CMAKE_BINARY_DIR} DIRECTORY) - file(RELATIVE_PATH RELPATH ${ITEM_REL} ${ITEM}) - - get_filename_component(RELPATH ${RELPATH} DIRECTORY) - get_filename_component(ITEMEXT ${ITEM} LAST_EXT) - - if("${ITEMEXT}" STREQUAL ".dll" OR "${ITEMEXT}" STREQUAL ".pdb") - string(CONCAT RELPATH "") - elseif ("${ITEMEXT}" STREQUAL ".so") - file(RELATIVE_PATH RELPATH "${ITEM_REL}/winuwp" ${ITEM}) - string(REGEX REPLACE "/" "\\\\" RELPATH ${RELPATH}) - string(CONCAT RELPATH "Assets\\Data") - elseif("${ITEMEXT}" STREQUAL ".dat") - string(CONCAT RELPATH "Assets\\Data") - else() - string(REGEX REPLACE "/" "\\\\" RELPATH ${RELPATH}) - string(CONCAT RELPATH "Assets\\Data\\" ${RELPATH}) - endif() - - cmake_print_variables(${RELPATH}) - - set_property(SOURCE ${ITEM} PROPERTY VS_DEPLOYMENT_CONTENT 1) - set_property(SOURCE ${ITEM} PROPERTY VS_DEPLOYMENT_LOCATION ${RELPATH}) -endforeach() - -add_executable (${BINARY_NAME} WIN32 - main.cpp - flutter_frameworkview.cpp - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - ${RESOURCE_FILES} - ${INSTALL_MANIFEST_CONTENT} -) -apply_standard_settings(${BINARY_NAME}) -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") -target_link_libraries(${BINARY_NAME} PRIVATE WindowsApp flutter flutter_wrapper_app) -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/winuwp/runner_uwp/CMakeSettings.json b/winuwp/runner_uwp/CMakeSettings.json deleted file mode 100644 index ba63a53..0000000 --- a/winuwp/runner_uwp/CMakeSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file. - "configurations": [ - { - "name": "Debug", - "generator": "Visual Studio 15 2017 Win64", - "configurationType": "Debug", - "inheritEnvironments": [ "msvc_x64_x64" ], - "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", - "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "", - "ctestCommandArgs": "" - }, - { - "name": "Release", - "generator": "Visual Studio 15 2017 Win64", - "configurationType": "Release", - "inheritEnvironments": [ "msvc_x64_x64" ], - "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", - "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", - "cmakeCommandArgs": "", - "buildCommandArgs": "", - "ctestCommandArgs": "" - } - ] -} diff --git a/winuwp/runner_uwp/Windows_TemporaryKey.pfx b/winuwp/runner_uwp/Windows_TemporaryKey.pfx deleted file mode 100644 index 1cad999..0000000 Binary files a/winuwp/runner_uwp/Windows_TemporaryKey.pfx and /dev/null differ diff --git a/winuwp/runner_uwp/appxmanifest.in b/winuwp/runner_uwp/appxmanifest.in deleted file mode 100644 index 570d424..0000000 --- a/winuwp/runner_uwp/appxmanifest.in +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - @SHORT_NAME@ - CMake Test Cert - Assets/StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - diff --git a/winuwp/runner_uwp/flutter_frameworkview.cpp b/winuwp/runner_uwp/flutter_frameworkview.cpp deleted file mode 100644 index bcdc73a..0000000 --- a/winuwp/runner_uwp/flutter_frameworkview.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "winrt/Windows.ApplicationModel.Core.h" -#include "winrt/Windows.Foundation.h" -#include "winrt/Windows.System.Profile.h" -#include "winrt/Windows.System.Threading.h" -#include "winrt/Windows.UI.Core.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -struct FlutterFrameworkView - : winrt::implements< - FlutterFrameworkView, - winrt::Windows::ApplicationModel::Core::IFrameworkView> { - // |winrt::Windows::ApplicationModel::Core::IFrameworkView| - void - Initialize(winrt::Windows::ApplicationModel::Core::CoreApplicationView const - &applicationView) { - - // Layout scaling must be disabled in the appinitialization phase in order - // to take effect correctly. - if (winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo() - .DeviceFamily() == L"Windows.Xbox") { - - bool result = winrt::Windows::UI::ViewManagement::ApplicationViewScaling:: - TrySetDisableLayoutScaling(true); - if (!result) { - OutputDebugString(L"Couldn't disable layout scaling"); - } - } - - main_view_ = applicationView; - main_view_.Activated({this, &FlutterFrameworkView::OnActivated}); - } - - // |winrt::Windows::ApplicationModel::Core::IFrameworkView| - void Uninitialize() { - main_view_.Activated(nullptr); - main_view_ = nullptr; - } - - // |winrt::Windows::ApplicationModel::Core::IFrameworkView| - void Load(winrt::hstring const &) {} - - // |winrt::Windows::ApplicationModel::Core::IFrameworkView| - void Run() { - winrt::Windows::UI::Core::CoreWindow window = - winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread(); - - winrt::Windows::UI::Core::CoreDispatcher dispatcher = window.Dispatcher(); - dispatcher.ProcessEvents( - winrt::Windows::UI::Core::CoreProcessEventsOption::ProcessUntilQuit); - } - - // |winrt::Windows::ApplicationModel::Core::IFrameworkView| - winrt::Windows::Foundation::IAsyncAction - SetWindow(winrt::Windows::UI::Core::CoreWindow const &window) { - - // Capture reference to window. - window_ = window; - - // Lay out the window's content within the region occupied by the - // CoreWindow. - auto appView = winrt::Windows::UI::ViewManagement::ApplicationView:: - GetForCurrentView(); - - appView.SetDesiredBoundsMode(winrt::Windows::UI::ViewManagement:: - ApplicationViewBoundsMode::UseCoreWindow); - - // Configure folder paths. - try { - winrt::Windows::Storage::StorageFolder folder = - winrt::Windows::ApplicationModel::Package::Current() - .InstalledLocation(); - - winrt::Windows::Storage::StorageFolder assets = - co_await folder.GetFolderAsync(L"Assets"); - winrt::Windows::Storage::StorageFolder data = - co_await assets.GetFolderAsync(L"data"); - winrt::Windows::Storage::StorageFolder flutter_assets = - co_await data.GetFolderAsync(L"flutter_assets"); - winrt::Windows::Storage::StorageFile icu_data = - co_await data.GetFileAsync(L"icudtl.dat"); - -#if NDEBUG - winrt::Windows::Storage::StorageFile aot_data = - co_await data.GetFileAsync(L"app.so"); -#endif - - std::wstring flutter_assets_path{flutter_assets.Path()}; - std::wstring icu_data_path{icu_data.Path()}; - std::wstring aot_data_path { -#if NDEBUG - aot_data.Path() -#endif - }; - - flutter::DartProject project(flutter_assets_path, icu_data_path, - aot_data_path); - - // Construct viewcontroller using the Window and project - flutter_view_controller_ = std::make_unique( - static_cast(winrt::get_abi(main_view_)), - static_cast(winrt::get_abi(launch_args_)), - project); - - // If plugins present, register them. - RegisterPlugins(flutter_view_controller_.get()->engine()); - } catch (winrt::hresult_error &err) { - winrt::Windows::UI::Popups::MessageDialog md = - winrt::Windows::UI::Popups::MessageDialog::MessageDialog( - L"There was a problem starting the engine: " + err.message()); - md.ShowAsync(); - } - } - - void OnActivated( - winrt::Windows::ApplicationModel::Core::CoreApplicationView const - &applicationView, - winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const - &args) { - // Activate the application window, making it visible and enabling it to - // receive events. - applicationView.CoreWindow().Activate(); - - // Capture launch args to later pass to Flutter. - launch_args_ = args; - } - - // Current CoreApplicationView. - winrt::Windows::ApplicationModel::Core::CoreApplicationView main_view_{ - nullptr}; - - // Current CoreWindow. - winrt::Windows::UI::Core::CoreWindow window_{nullptr}; - - // Current FlutterViewController. - std::unique_ptr flutter_view_controller_{ - nullptr}; - - // Launch args that were passed in on activation. - winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs - launch_args_; -}; diff --git a/winuwp/runner_uwp/main.cpp b/winuwp/runner_uwp/main.cpp deleted file mode 100644 index 1ce54b1..0000000 --- a/winuwp/runner_uwp/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ - -#include - -#include "winrt/Windows.ApplicationModel.Core.h" -#include "winrt/Windows.Foundation.h" -#include -#include -#include - -#include - -#include "flutter_frameworkview.cpp" - -struct App - : winrt::implements< - App, winrt::Windows::ApplicationModel::Core::IFrameworkViewSource> { - App() { view_ = winrt::make_self(); } - - // |winrt::Windows::ApplicationModel::Core::IFrameworkViewSource| - winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView() { - return view_.as(); - } - - winrt::com_ptr view_; -}; - -int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { - winrt::Windows::ApplicationModel::Core::CoreApplication::Run( - winrt::make()); -} diff --git a/winuwp/runner_uwp/resources.pri b/winuwp/runner_uwp/resources.pri deleted file mode 100644 index 7de03c9..0000000 Binary files a/winuwp/runner_uwp/resources.pri and /dev/null differ