arcane 6.1.1
arcane: ^6.1.1 copied to clipboard
A modified variant of shadcn_flutter along with new features & improvements. This package follows the changes of shadcn_flutter while also maintaining additional features & fixes.
example/lib/main.dart
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:arcane/arcane.dart';
import 'package:flutter/services.dart';
import 'package:gui_shape/geo/geo.dart';
import 'package:gui_shape/gui/gui.dart';
bool v = false;
String? vv;
void main() {
runZonedGuarded(() {
runApp("example", const ExampleArcaneApp());
}, (error, stackTrace) {
print("Error: $error");
print("Stack: $stackTrace");
});
}
class ExampleArcaneApp extends StatelessWidget {
const ExampleArcaneApp({super.key});
void didShortcut() {
print("YOU DID IT");
}
@override
Widget build(BuildContext context) => ArcaneShortcuts(
shortcuts: {
LogicalKeySet(
LogicalKeyboardKey.control,
LogicalKeyboardKey.alt,
LogicalKeyboardKey.keyF,
): didShortcut
},
child: const ArcaneApp(
home: HomeScreen(),
showPerformanceOverlay: false,
theme: ArcaneTheme(
themeMode: ThemeMode.system,
blurMode: ArcaneBlurMode.backdropFilter)));
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) => FillScreen(
gutter: false,
child: Center(
child: EncodedStrand(
b64: "fX0C7ZfPQg==",
base: 3,
),
),
);
}
class EncodedStrand extends StatelessWidget {
final String b64;
final int offset;
final int base;
const EncodedStrand(
{super.key, required this.b64, this.offset = 0, this.base = 3});
@override
Widget build(BuildContext context) {
String baseB = base64ToBaseN(b64, base);
String ch = charsets["hebrew"]!;
String encoded = "$ch${encodeToCustomBase(b64, ch)}";
String extractedCharset = extractCharset(encoded);
String redecoded = decodeFromCustomBase(
encoded.substring(extractedCharset.length), extractedCharset);
print(b64);
print(encoded);
print("CH = $extractedCharset");
print(redecoded);
print(ch.length);
List<Widget> shapes = [];
for (int i = 0; i < baseB.length; i++) {
int n = int.parse(baseB[i]) + offset;
shapes.add(NShape(sides: n));
}
return Wrap(
runAlignment: WrapAlignment.start,
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start,
children: shapes,
).padHorizontal(32);
}
}
class NShape extends StatelessWidget {
final int sides;
const NShape({super.key, this.sides = 3});
@override
Widget build(BuildContext context) => true
? Icon(getThing(sides))
: SizedBox(
width: 12,
height: 12,
child: Transform.rotate(
angle: 0,
child: GuiClipShape(
shape: GuiShapePolygon(sides: sides, startAngle: GeoAngle.zero),
child: Container(
color: Colors.white,
),
),
),
);
}
String base64ToBaseN(String base64Str, int n) {
if (n < 2 || n > 10) {
throw ArgumentError('Base n must be between 2 and 10');
}
// Decode base64 to bytes
Uint8List bytes = base64.decode(base64Str);
// Convert bytes to BigInt
BigInt num = BigInt.zero;
for (int byte in bytes) {
num = (num << 8) | BigInt.from(byte);
}
// Handle zero
if (num == BigInt.zero) {
return '0';
}
// Convert BigInt to base n
StringBuffer sb = StringBuffer();
while (num > BigInt.zero) {
BigInt rem = num % BigInt.from(n);
sb.write(rem.toInt());
num = num ~/ BigInt.from(n);
}
// Reverse the string to get correct order
String result = sb.toString().split('').reversed.join();
return result;
}
IconData getThing(int x) => switch (x) {
0 => Icons.circle,
1 => Icons.triangle,
2 => Icons.diamond,
3 => Icons.x,
_ => Icons.x
};
///////
String _c(int from, [int? to, Set<int>? not]) => to == null
? String.fromCharCode(from)
: List.generate(to - from, (i) => from + i)
.where((c) => not == null || !not.contains(c))
.map((i) => String.fromCharCode(i))
.join();
final Map<String, String> charsets = {
"gurmukhi": _c(0x0a01, 0x0a76, {
0x0a04,
0x0a0b,
0x0a0c,
0x0a0d,
0x0a0e,
0x0a11,
0x0a12,
0x0a29,
0x0a31,
0x0a34,
0x0a37,
0x0a3a,
0x0a3b,
0x0a3d,
0x0a43,
0x0a44,
0x0a45,
0x0a46,
0x0a49,
0x0a4a,
0x0a4e,
0x0a4f,
0x0a50,
0x0a52,
0x0a53,
0x0a54,
0x0a55,
0x0a56,
0x0a57,
0x0a58,
0x0a5d,
0x0a5f,
0x0a60,
0x0a61,
0x0a62,
0x0a63,
0x0a64,
0x0a65,
}),
"gujarati": _c(0x0a81, 0x0aff, {
0x0a84,
0x0a8e,
0x0a92,
0x0aa9,
0x0ab1,
0x0ab4,
0x0aba,
0x0abb,
0x0ac6,
0x0aca,
0x0ace,
0x0acf,
0x0ad1,
0x0ad2,
0x0ad3,
0x0ad4,
0x0ad5,
0x0ad6,
0x0ad7,
0x0ad8,
0x0ad9,
0x0ada,
0x0adb,
0x0adc,
0x0add,
0x0ade,
0x0adf,
0x0ae4,
0x0ae5,
0x0af2,
0x0af3,
0x0af4,
0x0af5,
0x0af6,
0x0af7,
0x0af8,
}),
"devanagari": _c(0x0900, 0x097f),
"nko": _c(0x07c0, 0x07ff, {0x07fc}),
"syriac": "${_c(0x0710, 0x072f)}${_c(0x074d, 0x074f)}",
"thaana": _c(0x0780, 0x07b1),
"arabic": "${_c(0x0600, 0x06ff, {
0x061A,
0x061D,
0x653
})}${_c(0x0750, 0x077f)}${_c(0x08a0, 0x08bd)}",
"arabicLine": "${_c(0x0600, 0x0605)}${_c(0x060e)}",
"latin": _c(0x00c0, 0x02af),
"greek": _c(0x0388, 0x03ff),
"cyrrilic": _c(0x0400, 0x052f, {
0x0483,
0x0484,
0x0485,
0x0486,
0x0487,
}),
"hebrew": _c(0x05d0, 0x05f2, {0x05ec, 0x05ed, 0x05ee, 0x05ef, 0x05eb}),
"armenian": _c(0x0531, 0x0588, {
0x0557,
0x0558,
0x0560,
0x0559,
0x055a,
0x055b,
0x055c,
0x055d,
0x055e,
0x055f,
}),
"bengali": _c(0x0980, 0x09fe, {
0x09D0,
0x09D8,
0x09CA,
0x0992,
0x09C5,
0x09D4,
0x09B1,
0x09B2,
0x09B3,
0x09BA,
0x09C6,
0x09B5,
0x09C2,
0x09C3,
0x098E,
0x09B4,
0x0984,
0x098d,
0x0991,
0x09a9,
0x09bb,
0x09c9,
0x09cf,
0x09d1,
0x09d2,
0x09d3,
0x09d5,
0x09d6,
0x09d9,
0x09da,
0x09db,
0x09de,
0x09e4,
0x09e5,
}),
};
extension XString on String {
String genAsCharset(int length) =>
List.generate(length, (index) => this[Random().nextInt(this.length)])
.join();
}
enum KeyMode { rancid, bars, regular }
String genKey({KeyMode keyMode = KeyMode.rancid}) {
if (keyMode == KeyMode.bars) {
return "iIlLjJ1".genAsCharset(16);
} else if (keyMode == KeyMode.regular) {
return "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"
.genAsCharset(32);
}
Random r = Random();
int length = 128;
String buf = "";
while (buf.length <= length) {
String charset =
charsets[charsets.keys.toList()[r.nextInt(charsets.length)]]!;
int c = r.nextInt(3);
if (c == 0) {
charset = charset.toLowerCase();
} else if (c == 1) {
charset = charset.toUpperCase();
}
buf += charset.genAsCharset(r.nextInt(8) + 4);
}
return buf.substring(0, length);
}
String generateSparkAPIKey() {
return "$sparkKeyHeader(${genKey(keyMode: KeyMode.regular)})";
}
String generateMageAPIKey() {
return "$mageKeyHeader(${genKey(keyMode: KeyMode.regular)})";
}
const sparkKeyHeader = "sprk";
const mageKeyHeader = "mage";
String encodeToCustomBase(String base64Input, String charset) {
if (base64Input.isEmpty) return '';
List<int> bytes = base64.decode(base64Input);
int n = charset.length;
if (n < 2) throw Exception('Charset must have at least 2 unique characters');
BigInt number = BigInt.zero;
for (int byte in bytes) {
number = (number << 8) | BigInt.from(byte & 0xFF);
}
int bitLength = bytes.length * 8;
if (bitLength == 0) return '';
double log2N = log(n) / log(2);
int outputLength = (bitLength / log2N).ceil().toInt();
List<int> digits = [];
BigInt base = BigInt.from(n);
while (number > BigInt.zero) {
digits.add((number % base).toInt());
number = number ~/ base;
}
while (digits.length < outputLength) {
digits.add(0);
}
digits = digits.reversed.toList();
StringBuffer sb = StringBuffer();
for (int digit in digits) {
sb.write(charset[digit]);
}
return sb.toString();
}
String extractCharset(String encoded) {
List<String> x = [];
for (int i = 0; i < encoded.length; i++) {
if (!x.contains(encoded[i])) {
x.add(encoded[i]);
} else {
break;
}
}
return x.join();
}
String decodeFromCustomBase(String encoded, String charset) {
if (encoded.isEmpty) return '';
int outputLength = encoded.length;
int n = charset.length;
if (n < 2) throw Exception('Charset must have at least 2 unique characters');
Map<String, int> charToDigit = {};
for (int i = 0; i < n; i++) {
String ch = charset[i];
if (charToDigit.containsKey(ch))
throw Exception('Charset must have unique characters');
charToDigit[ch] = i;
}
BigInt number = BigInt.zero;
BigInt base = BigInt.from(n);
for (int i = 0; i < outputLength; i++) {
String ch = encoded[i];
int? digit = charToDigit[ch];
if (digit == null) throw Exception('Invalid character in encoded string');
number = number * base + BigInt.from(digit);
}
double log2N = log(n) / log(2);
double maxBits = outputLength * log2N;
double minBits = (outputLength - 1) * log2N;
int byteLen = (maxBits / 8).floor();
int bitLen = byteLen * 8;
if (!(bitLen > minBits && bitLen <= maxBits)) {
throw Exception('Invalid encoded length for this charset');
}
List<int> bytes = List<int>.filled(byteLen, 0);
BigInt temp = number;
for (int i = byteLen - 1; i >= 0; i--) {
bytes[i] = (temp & BigInt.from(0xFF)).toInt();
temp = temp >> 8;
}
if (temp != BigInt.zero) {
throw Exception('Number too large for the computed byte length');
}
return base64.encode(bytes);
}