我是廣告,點擊一下吧!
標籤
#Flutter (17) 、 #PHP (9) 、 #Laravel (7) 、 #MySQL (5) 、 #Mac (5) 、 #Dart (5) 、 #Android (3) 、 #List (2) 、 #Widget (2) 、 #Carbon (2) 、 #IDE (2) 、 #VS Code (2) 、 #Linux (2) 、 #Shell Script (2) 、 #Cursor Pagination (1) 、 #Pagination (1) 、 #floorMonth (1) 、 #subMonthNoOverflow (1) 、 #資安 (1) 、 #addMonthNoOverflow (1) 、 #subMonth (1) 、 #MySQL 效能 (1) 、 #Mac M1 (1) 、 #個人空間 (1) 、 #Android Splash Screen (1) 、 #Android vector (1) 、 #SVG (1) 、 #Directory Structure (1) 、 #SQL Injection (1) 、 #createFromTimestamp (1)因為個人 Mac 是 M1 記憶體也只有 8G,空間又不足,每次 Build 都會跑到電腦很 Lag,所以轉用 Github Action 來 Build,避免電腦一堆垃圾與佔用記憶體。
Guthub 免費提供每月 2000 分鐘的額度,可以從 Actions Usage Metrics 觀看使用量。
| Plan | Artifact storage | Minutes (per month) | Cache storage |
|---|---|---|---|
| GitHub Free | 500 MB | 2,000 | 10 GB |
| GitHub Pro | 1 GB | 3,000 | 10 GB |
| GitHub Free for organizations | 500 MB | 2,000 | 10 GB |
| GitHub Team | 2 GB | 3,000 | 10 GB |
| GitHub Enterprise Cloud | 50 GB | 50,000 | 10 GB |
.github/workflows/xxx.yml ,一個 xxx.yml 檔,就是一個工作流程,一個專案可以一次設定多個 workflow。
要使用 Action 上傳到 Github Release 就必須先設定一組 Token,產生方式為 右上角點你的頭像 > Settings > Developer settings > Personal access tokens > Tokens (classic) > Generate new token (classic),勾選 repo、write:packages 產生。
Secrets 是用來將 .jks、Token、等機敏資料加密存在 Github,使用到時再讀出來使用,避免把機敏資料上到 Git Commit。
一個 Secret 可從 GitHub Repository > Settings > Secrets and variables > Actions > New repository secret 新增即可在 .yml 內使用 ${{ secrets.KEY }} 替代。
| Secret 名稱 | 用途說明 |
|---|---|
ID_RSA | SFTP SSH Key |
KEYSTORE_BASE64 | Android keystore 的 Base64 |
KEY_ALIAS | Keystore 的 Alias |
KEY_PASSWORD | Key 的密碼 |
STORE_PASSWORD | Keystore 的密碼 |
PERSONAL_ACCESS_TOKEN | GitHub Personal Access Token |
Flutter 提供 launch_background.xml 放置 Android 的 Splash Screen。
一般教學都是使用 PNG 圖片,但實際使用時發現很模糊,所以需要使用向量圖檔。
但直接將檔案改成 SVG 會出現 Error: The file name must end with .xml or .png,不支援 SVG 檔案,所以可使用 https://svg2vector.com 快速將 SVG 轉成 Android 的 vector 物件替換。

mtsung@MTsung-Toby-MacBook-3 ~ % du -sh /Users/mtsung/Library/Application\ Support/Kiro/User/globalStorage/kiro.kiroagent
5.1G /Users/mtsung/Library/Application Support/Kiro/User/globalStorage/kiro.kiroagent 稍微研究裡面檔案是 Kiro 的聊天記錄,移除後不影響功能,直接砍了。 在 Flutter 中使用 markdown_widget 與 flutter_math_fork,讓 Markdown 支援 LaTeX 數學公式渲染。

dependencies:
markdown_widget: ^2.3.2+8
flutter_math_fork: ^0.7.0 import 'package:flutter/material.dart';
import 'package:markdown_widget/markdown_widget.dart';
import 'package:flutter_math_fork/flutter_math.dart';
import 'package:markdown/markdown.dart' as m;
SpanNodeGeneratorWithTag latexGenerator =
SpanNodeGeneratorWithTag(tag: _latexTag, generator: (e, config, visitor) => LatexNode(e.attributes, e.textContent, config));
const _latexTag = 'latex';
class LatexSyntax extends m.InlineSyntax {
LatexSyntax() : super(r'(\$\$[\s\S]+\$\$)|(\$.+?\$)');
@override
bool onMatch(m.InlineParser parser, Match match) {
final input = match.input;
final matchValue = input.substring(match.start, match.end);
String content = '';
bool isInline = true;
const blockSyntax = '\$\$';
const inlineSyntax = '\$';
if (matchValue.startsWith(blockSyntax) && matchValue.endsWith(blockSyntax) && (matchValue != blockSyntax)) {
content = matchValue.substring(2, matchValue.length - 2);
isInline = false;
} else if (matchValue.startsWith(inlineSyntax) && matchValue.endsWith(inlineSyntax) && matchValue != inlineSyntax) {
content = matchValue.substring(1, matchValue.length - 1);
}
m.Element el = m.Element.text(_latexTag, matchValue);
el.attributes['content'] = content;
el.attributes['isInline'] = '$isInline';
parser.addNode(el);
return true;
}
}
class LatexNode extends SpanNode {
final Map<String, String> attributes;
final String textContent;
final MarkdownConfig config;
LatexNode(this.attributes, this.textContent, this.config);
@override
InlineSpan build() {
final content = attributes['content'] ?? '';
final isInline = attributes['isInline'] == 'true';
final style = parentStyle ?? config.p.textStyle;
if (content.isEmpty) return TextSpan(style: style, text: textContent);
final latex = Math.tex(
content,
mathStyle: MathStyle.text,
textStyle: style.copyWith(color: Colors.black),
textScaleFactor: 1,
onErrorFallback: (error) {
return Text(textContent, style: style.copyWith(color: Colors.red));
},
);
return WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: !isInline
? Container(
width: double.infinity,
margin: EdgeInsets.symmetric(vertical: 16),
child: Center(child: latex),
)
: latex,
);
}
}
import 'package:project_name/latex.dart';
import 'package:markdown_widget/markdown_widget.dart';
......
MarkdownWidget(
data: '''\$\$f(X,n) = X_n + X_{n-1}\$\$
\$\$
M =
\\begin{bmatrix}
\\frac{5}{6} & \\frac{1}{6} & 0 \\\\[0.3em]
\\frac{5}{6} & 0 & \\frac{1}{6} \\\\[0.3em]
0 & \\frac{5}{6} & \\frac{1}{6}
\\end{bmatrix}
\$\$''',
markdownGenerator: MarkdownGenerator(
inlineSyntaxList: [LatexSyntax()],
generators: [latexGenerator],
),
),
......