Skip to content

Commit 805bacd

Browse files
committed
Push 1.1.0
1 parent c7e2668 commit 805bacd

File tree

6 files changed

+148
-25
lines changed

6 files changed

+148
-25
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 1.1.0
2+
3+
* Included `colors.json` for last resort if enabled offline as a last resort when
4+
create new instance of `GitHubColour`.
5+
* Allows get all data in `GitHubColour` to `ColorSwatch`.
6+
* Provides `Set` with all availabled languages name.
7+
18
## 1.0.0
29

310
* Change `GitHubColours.find`'s fallback method.

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,21 @@ Receiving [ozh's github-colors](https://github.com/ozh/github-colors) repository
77

88
## Usage
99

10-
You can either initalized `GitHubColour` before `runApp(Widget)`:
10+
You can either initalized `GitHubColour` before `runApp(Widget)` (Call it after `WidgetsFlutterBinding.ensureInitialized()` if want to get data from offline):
1111

1212
```dart
13+
// With offline last resort
1314
void main() async {
15+
WidgetsFlutterBinding.ensureInitialized();
1416
await GitHubColour.getInstance();
1517
runApp(const YourApp());
1618
}
19+
20+
// Without offline last resort
21+
void main() async {
22+
await GitHubColour.getInstance(offlineLastResort = false);
23+
runApp(const YourApp());
24+
}
1725
```
1826

1927
then uses `getExistedInstance()` inside the `Widget`:
@@ -27,7 +35,7 @@ class YourAppWidget extends StatelessWidget {
2735
}
2836
```
2937

30-
or wrapped into `FutureBuilder` directly in `State`'s `initState` (not recommended uses `getInstance()` directly in `FutureBuilder`):
38+
or wrapped into `FutureBuilder` with initalized `Future<GitHubColour>` variable into `State`'s `initState` (not recommended uses `getInstance()` directly in `FutureBuilder`):
3139

3240
```dart
3341
class _YourAnotherAppWidgetState extends State<YourAnotherAppWidget> {
@@ -54,6 +62,8 @@ class _YourAnotherAppWidgetState extends State<YourAnotherAppWidget> {
5462
This package supported caching system as a backup when making request failed. It uses LZMA compress data and store as a file under temporary directory (for VM)
5563
or store as `shared_preference` (for Web, which is `LocalStorage`).
5664

65+
If no cache available, by default, `GitHubColour.getInstance()` will uses [local's `colors.json`](lib/colors.json) as last resort. However, this package will not make a new release when newer commit of `color.json` pushed since it minified that ensure the package can be downloaded as fast as possible.
66+
5767
## Note for American English developers
5868

5969
It's provide alias class `GitHubColor` for who uses "color" mostly.

example/lib/main.dart

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@ import 'package:flutter/material.dart';
22
import 'package:github_colour/github_colour.dart';
33

44
void main() async {
5+
// Required if want to uses offline JSON data as last resort.
6+
WidgetsFlutterBinding.ensureInitialized();
57
// Construct an instance for future uses.
68
await GitHubColour.getInstance();
9+
10+
// It does not required binding if disabled offline last resort
11+
/*
12+
await GitHubColour.getInstance(offlineLastResort: false);
13+
*/
14+
715
runApp(const App());
816
}
917

@@ -47,7 +55,10 @@ class _GitHubColourDemoState extends State<GitHubColourDemo> {
4755
@override
4856
Widget build(BuildContext context) => Scaffold(
4957
appBar: AppBar(
50-
backgroundColor: GitHubColour.getExistedInstance().find(_lang),
58+
// Change app bar background colour when enter the language.
59+
backgroundColor: GitHubColour.getExistedInstance().find(_lang,
60+
// Use default colour if unexisted.
61+
onUndefined: () => GitHubColour.defaultColour),
5162
title: const Text("GitHub colour")),
5263
body: Center(
5364
child: Column(
@@ -58,6 +69,7 @@ class _GitHubColourDemoState extends State<GitHubColourDemo> {
5869
margin: const EdgeInsets.all(12),
5970
constraints: const BoxConstraints(maxWidth: 350),
6071
child: TextField(
72+
// Enter the language here
6173
textInputAction: TextInputAction.go,
6274
onSubmitted: (_) {
6375
_changeColour();
@@ -68,6 +80,7 @@ class _GitHubColourDemoState extends State<GitHubColourDemo> {
6880
autocorrect: false)),
6981
const Divider(height: 8, indent: 1.5, thickness: 0.25),
7082
SizedBox(
83+
// Submit button
7184
width: 80,
7285
height: 35,
7386
child: ElevatedButton(

lib/colors.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

lib/github_colour.dart

Lines changed: 111 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,57 @@
44
library github_colour;
55

66
import 'dart:convert';
7+
import 'dart:io';
78

8-
import 'package:flutter/widgets.dart' show Color;
9+
import 'package:flutter/services.dart';
10+
import 'package:flutter/widgets.dart'
11+
show Color, ColorSwatch, WidgetsFlutterBinding;
912
import 'package:http/http.dart' as http show get;
1013
import 'package:meta/meta.dart' show sealed;
1114

1215
import 'src/cache/cache.dart';
1316

17+
const String _src =
18+
"https://raw.githubusercontent.com/ozh/github-colors/master/colors.json";
19+
1420
/// A handler when no language data found in [GitHubColour.find].
1521
typedef LanguageUndefinedHandler = Color Function();
1622

23+
/// An [Error] that can not fetch [GitHubColour] data.
24+
abstract class GitHubColourLoadFailedError extends Error {
25+
final String _message;
26+
27+
GitHubColourLoadFailedError._(
28+
[this._message =
29+
"There are some unexpected error when loading resources."]);
30+
31+
@override
32+
String toString() => _message;
33+
}
34+
1735
/// An [Error] thrown when response unsuccessfully and no cache can be used.
18-
class GitHubColourLoadFailedError extends Error {
36+
class GitHubColourHTTPLoadFailedError extends GitHubColourLoadFailedError {
1937
/// HTTP response code when fetching colour data.
2038
final int responseCode;
2139

22-
GitHubColourLoadFailedError._(this.responseCode)
23-
: assert(responseCode != 200);
40+
GitHubColourHTTPLoadFailedError._(this.responseCode)
41+
: assert(responseCode != 200),
42+
super._();
2443

2544
@override
2645
String toString() =>
2746
"GitHubColourLoadFailedError: Can not receive GitHub language colour from server with HTTP code $responseCode.";
2847
}
2948

49+
/// An [Error] thrown when no resources available to initalize [GitHubColour].
50+
class GitHubColourNoAvailableResourceError extends GitHubColourLoadFailedError {
51+
GitHubColourNoAvailableResourceError._() : super._();
52+
53+
@override
54+
String toString() =>
55+
"GitHubColourNoAvailableResourceError: Unable to read GitHub colour data with all available sources.";
56+
}
57+
3058
/// An [Error] when no colour data of the language.
3159
class UndefinedLanguageColourError extends ArgumentError {
3260
/// Undefined language name.
@@ -37,6 +65,15 @@ class UndefinedLanguageColourError extends ArgumentError {
3765
"UndefinedLanguageColourError");
3866
}
3967

68+
Map<String, Color> _colourReader(String json) =>
69+
(jsonDecode(json) as Map<String, dynamic>)
70+
.map<String, Color>((language, node) {
71+
String hex = node["color"] ?? GitHubColour.defaultColourHex;
72+
hex = "FF${hex.substring(1).toUpperCase()}";
73+
74+
return MapEntry(language, Color(int.parse(hex, radix: 16)));
75+
});
76+
4077
/// A class for getting GitHub language colour.
4178
@sealed
4279
class GitHubColour {
@@ -56,29 +93,56 @@ class GitHubColour {
5693
///
5794
/// If no instance created, it will construct and will be reused when
5895
/// [getInstance] or [getExistedInstance] called again.
59-
static Future<GitHubColour> getInstance() async {
96+
///
97+
/// If [offlineLastResort] enabled, it loads package's `colors.json` for
98+
/// getting colour data offline. And it must be called after
99+
/// [WidgetsFlutterBinding.ensureInitialized] invoked in `main()` method to
100+
/// allow get offline colour data from [rootBundle].
101+
///
102+
/// When all resources failed, it throws
103+
/// [GitHubColourNoAvailableResourceError]. If [offlineLastResort] disabled,
104+
/// either [GitHubColourHTTPLoadFailedError] (if network available) or
105+
/// [SocketException] (without network access) throws.
106+
///
107+
/// [offlineLastResort] only works when [getInstance] invoked first time
108+
/// in entire runtime. This parameter will be ignored once the instance
109+
/// constructed.
110+
static Future<GitHubColour> getInstance(
111+
{bool offlineLastResort = true}) async {
60112
if (_instance == null) {
61-
final Uri ghc = Uri.parse(
62-
"https://raw.githubusercontent.com/ozh/github-colors/master/colors.json");
63-
64-
var resp = await http.get(ghc);
65-
113+
final Uri ghc = Uri.parse(_src);
66114
Map<String, Color> ghjson;
67115

68-
if (resp.statusCode != 200) {
116+
bool cacheSource = false;
117+
118+
try {
119+
var resp = await http.get(ghc);
120+
if (resp.statusCode != 200) {
121+
throw GitHubColourHTTPLoadFailedError._(resp.statusCode);
122+
}
123+
ghjson = _colourReader(resp.body);
124+
} catch (neterr) {
69125
try {
70126
ghjson = await getCache();
71-
} catch (e) {
72-
throw GitHubColourLoadFailedError._(resp.statusCode);
127+
cacheSource = true;
128+
} catch (cerr) {
129+
if (!offlineLastResort) {
130+
// When offline last resort disabled.
131+
throw neterr;
132+
}
133+
134+
try {
135+
// Use provided JSON file as last resort.
136+
ghjson = _colourReader(await rootBundle.loadString(
137+
"packages/github_colour/colors.json",
138+
cache: false));
139+
} catch (bundleerr) {
140+
throw GitHubColourNoAvailableResourceError._();
141+
}
73142
}
74-
} else {
75-
ghjson = (jsonDecode(resp.body) as Map<String, dynamic>)
76-
.map<String, Color>((key, value) {
77-
String hex = value["color"] ?? defaultColourHex;
78-
hex = "FF${hex.substring(1).toUpperCase()}";
79-
80-
return MapEntry(key, Color(int.parse(hex, radix: 16)));
81-
});
143+
}
144+
145+
if (!cacheSource) {
82146
await saveCache(ghjson);
83147
}
84148

@@ -113,6 +177,32 @@ class GitHubColour {
113177

114178
/// Check does the [language] existed.
115179
bool contains(String language) => _githubLangColour.containsKey(language);
180+
181+
/// Export all recorded of [GitHubColour] data to [ColorSwatch] with [String]
182+
/// as index.
183+
///
184+
/// By default, [includeDefault] set as `false`. If `true`, the [ColorSwatch]
185+
/// will appended `__default__` index for repersenting [defaultColour] which
186+
/// also is [ColorSwatch]'s default colour.
187+
///
188+
/// If [overridePrimaryColour] applied and [find] existed [Color], it applied
189+
/// as [ColorSwatch]'s primary colour instead of [defaultColour].
190+
ColorSwatch<String> toSwatch(
191+
{bool includeDefault = false, String? overridePrimaryColour}) {
192+
Map<String, Color> modGLC = Map.from(_githubLangColour);
193+
194+
if (includeDefault) {
195+
modGLC["__default__"] = defaultColour;
196+
}
197+
198+
return ColorSwatch(
199+
find(overridePrimaryColour ?? "_", onUndefined: () => defaultColour)
200+
.value,
201+
modGLC);
202+
}
203+
204+
/// Get a [Set] of [String] that contains all recorded langauages name.
205+
Set<String> get listedLanguage => Set.unmodifiable(_githubLangColour.keys);
116206
}
117207

118208
/// Alias type for repersenting "colour" in American English which does exactly

pubspec.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: github_colour
22
description: Receive ozh's GitHub colour to Flutter's colour implementation with caching and fallback.
3-
version: 1.0.0
3+
version: 1.1.0
44
homepage: https://www.rk0cc.xyz
55
repository: https://github.com/rk0cc/github_colour_flutter
66
environment:
@@ -17,3 +17,5 @@ dependencies:
1717
shared_preferences: ^2.0.13
1818
flutter:
1919
uses-material-design: true
20+
assets:
21+
- packages/github_colour/colors.json

0 commit comments

Comments
 (0)