formatting

This commit is contained in:
Adrian Baumgart 2024-07-25 17:37:17 +02:00
parent 0eea6ee9a2
commit ba058e2af3
Signed by: rainloreley
SSH Key Fingerprint: SHA256:DrGrohIPualL1UkyUym0K4C+uC5njuzPFBdXgtVZntM
11 changed files with 216 additions and 192 deletions

View File

@ -14,11 +14,9 @@ enum ConditionDeviceType {
} }
throw ArgumentError("Invalid type $api"); throw ArgumentError("Invalid type $api");
} }
} }
extension ConditionTypeExtension on ConditionDeviceType { extension ConditionTypeExtension on ConditionDeviceType {
String get api { String get api {
switch (this) { switch (this) {
case ConditionDeviceType.IOS: case ConditionDeviceType.IOS:
@ -29,6 +27,7 @@ extension ConditionTypeExtension on ConditionDeviceType {
return "desktop"; return "desktop";
} }
} }
String get humanReadable { String get humanReadable {
switch (this) { switch (this) {
case ConditionDeviceType.IOS: case ConditionDeviceType.IOS:

View File

@ -11,8 +11,9 @@ class RedirectRule {
RedirectRule.fromJson(Map<String, dynamic> json) RedirectRule.fromJson(Map<String, dynamic> json)
: longUrl = json["longUrl"], : longUrl = json["longUrl"],
priority = json["priority"], priority = json["priority"],
conditions = (json["conditions"] as List<dynamic>).map((e) conditions = (json["conditions"] as List<dynamic>)
=> RedirectRuleCondition.fromJson(e)).toList(); .map((e) => RedirectRuleCondition.fromJson(e))
.toList();
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {

View File

@ -5,8 +5,8 @@ class RedirectRuleCondition {
String matchValue; String matchValue;
String? matchKey; String? matchKey;
RedirectRuleCondition(String type, this.matchValue, this.matchKey) : RedirectRuleCondition(String type, this.matchValue, this.matchKey)
type = RedirectRuleConditionType.fromApi(type); : type = RedirectRuleConditionType.fromApi(type);
RedirectRuleCondition.fromJson(Map<String, dynamic> json) RedirectRuleCondition.fromJson(Map<String, dynamic> json)
: type = RedirectRuleConditionType.fromApi(json["type"]), : type = RedirectRuleConditionType.fromApi(json["type"]),
@ -14,10 +14,6 @@ class RedirectRuleCondition {
matchKey = json["matchKey"]; matchKey = json["matchKey"];
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {"type": type.api, "matchValue": matchValue, "matchKey": matchKey};
"type": type.api,
"matchValue": matchValue,
"matchKey": matchKey
};
} }
} }

View File

@ -14,11 +14,9 @@ enum RedirectRuleConditionType {
} }
throw ArgumentError("Invalid type $api"); throw ArgumentError("Invalid type $api");
} }
} }
extension ConditionTypeExtension on RedirectRuleConditionType { extension ConditionTypeExtension on RedirectRuleConditionType {
String get api { String get api {
switch (this) { switch (this) {
case RedirectRuleConditionType.DEVICE: case RedirectRuleConditionType.DEVICE:
@ -29,6 +27,7 @@ extension ConditionTypeExtension on RedirectRuleConditionType {
return "query-param"; return "query-param";
} }
} }
String get humanReadable { String get humanReadable {
switch (this) { switch (this) {
case RedirectRuleConditionType.DEVICE: case RedirectRuleConditionType.DEVICE:

View File

@ -12,8 +12,9 @@ FutureOr<Either<List<RedirectRule>, Failure>> apiGetRedirectRules(
String? serverUrl, String? serverUrl,
String apiVersion) async { String apiVersion) async {
try { try {
final response = final response = await http.get(
await http.get(Uri.parse("$serverUrl/rest/v$apiVersion/short-urls/$shortCode/redirect-rules"), Uri.parse(
"$serverUrl/rest/v$apiVersion/short-urls/$shortCode/redirect-rules"),
headers: { headers: {
"X-Api-Key": apiKey ?? "", "X-Api-Key": apiKey ?? "",
}); });
@ -22,9 +23,10 @@ FutureOr<Either<List<RedirectRule>, Failure>> apiGetRedirectRules(
var jsonBody = jsonDecode(response.body) as Map<String, dynamic>; var jsonBody = jsonDecode(response.body) as Map<String, dynamic>;
// convert json array to object array // convert json array to object array
List<RedirectRule> redirectRules = (jsonBody["redirectRules"] List<RedirectRule> redirectRules =
as List<dynamic>).map((e) (jsonBody["redirectRules"] as List<dynamic>)
=> RedirectRule.fromJson(e)).toList(); .map((e) => RedirectRule.fromJson(e))
.toList();
return left(redirectRules); return left(redirectRules);
} else { } else {

View File

@ -14,13 +14,16 @@ FutureOr<Either<bool, Failure>> apiSetRedirectRules(
String apiVersion) async { String apiVersion) async {
try { try {
Map<String, dynamic> body = {}; Map<String, dynamic> body = {};
List<Map<String, dynamic>> redirectRulesJson = redirectRules.map((e) => e.toJson()).toList(); List<Map<String, dynamic>> redirectRulesJson =
redirectRules.map((e) => e.toJson()).toList();
body["redirectRules"] = redirectRulesJson; body["redirectRules"] = redirectRulesJson;
final response = final response = await http.post(
await http.post(Uri.parse("$serverUrl/rest/v$apiVersion/short-urls/$shortCode/redirect-rules"), Uri.parse(
"$serverUrl/rest/v$apiVersion/short-urls/$shortCode/redirect-rules"),
headers: { headers: {
"X-Api-Key": apiKey ?? "", "X-Api-Key": apiKey ?? "",
}, body: jsonEncode(body)); },
body: jsonEncode(body));
if (response.statusCode == 200) { if (response.statusCode == 200) {
return left(true); return left(true);
} else { } else {

View File

@ -127,6 +127,7 @@ class ServerManager {
FutureOr<Either<List<ShortURL>, Failure>> getRecentShortUrls() async { FutureOr<Either<List<ShortURL>, Failure>> getRecentShortUrls() async {
return apiGetRecentShortUrls(apiKey, serverUrl, apiVersion); return apiGetRecentShortUrls(apiKey, serverUrl, apiVersion);
} }
/// Gets redirect rules for a given short URL (code) /// Gets redirect rules for a given short URL (code)
FutureOr<Either<List<RedirectRule>, Failure>> getRedirectRules( FutureOr<Either<List<RedirectRule>, Failure>> getRedirectRules(
String shortCode) async { String shortCode) async {
@ -136,7 +137,8 @@ class ServerManager {
/// Sets redirect rules for a given short URL (code) /// Sets redirect rules for a given short URL (code)
FutureOr<Either<bool, Failure>> setRedirectRules( FutureOr<Either<bool, Failure>> setRedirectRules(
String shortCode, List<RedirectRule> redirectRules) async { String shortCode, List<RedirectRule> redirectRules) async {
return apiSetRedirectRules(shortCode, redirectRules, apiKey, serverUrl, apiVersion); return apiSetRedirectRules(
shortCode, redirectRules, apiKey, serverUrl, apiVersion);
} }
} }

View File

@ -11,8 +11,8 @@ void main() {
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
const MyApp({super.key}); const MyApp({super.key});
static final ColorScheme _defaultLightColorScheme = ColorScheme static final ColorScheme _defaultLightColorScheme =
.fromSeed(seedColor: Colors.blue); ColorScheme.fromSeed(seedColor: Colors.blue);
static final _defaultDarkColorScheme = ColorScheme.fromSeed( static final _defaultDarkColorScheme = ColorScheme.fromSeed(
brightness: Brightness.dark, brightness: Brightness.dark,

View File

@ -50,7 +50,8 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''', CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.''',
version: r'^1.0.5', version: r'^1.0.5',
homepage: null, homepage: null,
repository: r'https://github.com/flutter/packages/tree/main/third_party/packages/cupertino_icons', repository:
r'https://github.com/flutter/packages/tree/main/third_party/packages/cupertino_icons',
), ),
const License( const License(
name: r'dartz', name: r'dartz',
@ -286,7 +287,8 @@ SOFTWARE.
''', ''',
version: r'^1.6.6', version: r'^1.6.6',
homepage: null, homepage: null,
repository: r'https://github.com/material-foundation/flutter-packages/tree/main/packages/dynamic_color', repository:
r'https://github.com/material-foundation/flutter-packages/tree/main/packages/dynamic_color',
), ),
const License( const License(
name: r'flutter', name: r'flutter',
@ -346,7 +348,8 @@ SOFTWARE.
''', ''',
version: r'^0.13.1', version: r'^0.13.1',
homepage: r'https://github.com/fluttercommunity/flutter_launcher_icons', homepage: r'https://github.com/fluttercommunity/flutter_launcher_icons',
repository: r'https://github.com/fluttercommunity/flutter_launcher_icons/', repository:
r'https://github.com/fluttercommunity/flutter_launcher_icons/',
), ),
const License( const License(
name: r'flutter_lints', name: r'flutter_lints',
@ -378,7 +381,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''', ''',
version: r'^3.0.1', version: r'^3.0.1',
homepage: null, homepage: null,
repository: r'https://github.com/flutter/packages/tree/main/packages/flutter_lints', repository:
r'https://github.com/flutter/packages/tree/main/packages/flutter_lints',
), ),
const License( const License(
name: r'flutter_process_text', name: r'flutter_process_text',
@ -446,7 +450,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''', OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
version: r'^9.0.0', version: r'^9.0.0',
homepage: null, homepage: null,
repository: r'https://github.com/mogol/flutter_secure_storage/tree/develop/flutter_secure_storage', repository:
r'https://github.com/mogol/flutter_secure_storage/tree/develop/flutter_secure_storage',
), ),
const License( const License(
name: r'flutter_sharing_intent', name: r'flutter_sharing_intent',
@ -652,7 +657,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License.''', limitations under the License.''',
version: r'^1.1.1', version: r'^1.1.1',
homepage: r'https://github.com/bhagat-techind/flutter_sharing_intent.git', homepage:
r'https://github.com/bhagat-techind/flutter_sharing_intent.git',
repository: null, repository: null,
), ),
const License( const License(
@ -815,7 +821,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''', ''',
version: r'^4.0.2', version: r'^4.0.2',
homepage: r'https://plus.fluttercommunity.dev/', homepage: r'https://plus.fluttercommunity.dev/',
repository: r'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus/package_info_plus', repository:
r'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus/package_info_plus',
), ),
const License( const License(
name: r'qr_flutter', name: r'qr_flutter',
@ -883,7 +890,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''', ''',
version: r'^2.2.2', version: r'^2.2.2',
homepage: null, homepage: null,
repository: r'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences', repository:
r'https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences',
), ),
const License( const License(
name: r'tuple', name: r'tuple',
@ -943,7 +951,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''', ''',
version: r'^6.2.4', version: r'^6.2.4',
homepage: null, homepage: null,
repository: r'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher', repository:
r'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher',
), ),
]; ];
} }

View File

@ -13,7 +13,8 @@ class RedirectRulesDetailView extends StatefulWidget {
final ShortURL shortURL; final ShortURL shortURL;
@override @override
State<RedirectRulesDetailView> createState() => _RedirectRulesDetailViewState(); State<RedirectRulesDetailView> createState() =>
_RedirectRulesDetailViewState();
} }
class _RedirectRulesDetailViewState extends State<RedirectRulesDetailView> { class _RedirectRulesDetailViewState extends State<RedirectRulesDetailView> {
@ -30,7 +31,8 @@ class _RedirectRulesDetailViewState extends State<RedirectRulesDetailView> {
} }
Future<void> loadRedirectRules() async { Future<void> loadRedirectRules() async {
final response = await globals.serverManager.getRedirectRules(widget.shortURL.shortCode); final response =
await globals.serverManager.getRedirectRules(widget.shortURL.shortCode);
response.fold((l) { response.fold((l) {
setState(() { setState(() {
redirectRules = l; redirectRules = l;
@ -56,7 +58,8 @@ class _RedirectRulesDetailViewState extends State<RedirectRulesDetailView> {
} }
void _saveRedirectRules() async { void _saveRedirectRules() async {
final response = await globals.serverManager.setRedirectRules(widget.shortURL.shortCode, redirectRules); final response = await globals.serverManager
.setRedirectRules(widget.shortURL.shortCode, redirectRules);
response.fold((l) { response.fold((l) {
Navigator.pop(context); Navigator.pop(context);
}, (r) { }, (r) {
@ -131,16 +134,14 @@ class _RedirectRulesDetailViewState extends State<RedirectRulesDetailView> {
const Text( const Text(
"No Redirect Rules", "No Redirect Rules",
style: TextStyle( style: TextStyle(
fontSize: 24, fontSize: 24, fontWeight: FontWeight.bold),
fontWeight: FontWeight.bold),
), ),
Padding( Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Text( child: Text(
'Adding redirect rules will be supported soon!', 'Adding redirect rules will be supported soon!',
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16, color: Colors.grey[600]),
color: Colors.grey[600]),
), ),
) )
], ],
@ -151,14 +152,18 @@ class _RedirectRulesDetailViewState extends State<RedirectRulesDetailView> {
(BuildContext context, int index) { (BuildContext context, int index) {
return _ListCell( return _ListCell(
redirectRule: redirectRules[index], redirectRule: redirectRules[index],
moveUp: index == 0 ? null : () { moveUp: index == 0
? null
: () {
setState(() { setState(() {
redirectRules[index].priority -= 1; redirectRules[index].priority -= 1;
redirectRules[index - 1].priority += 1; redirectRules[index - 1].priority += 1;
}); });
_sortListByPriority(); _sortListByPriority();
}, },
moveDown: index == (redirectRules.length - 1) ? null : () { moveDown: index == (redirectRules.length - 1)
? null
: () {
setState(() { setState(() {
redirectRules[index].priority += 1; redirectRules[index].priority += 1;
redirectRules[index + 1].priority -= 1; redirectRules[index + 1].priority -= 1;
@ -180,7 +185,8 @@ class _RedirectRulesDetailViewState extends State<RedirectRulesDetailView> {
} }
class _ListCell extends StatefulWidget { class _ListCell extends StatefulWidget {
const _ListCell({super.key, const _ListCell(
{super.key,
required this.redirectRule, required this.redirectRule,
required this.moveUp, required this.moveUp,
required this.moveDown, required this.moveDown,
@ -196,7 +202,6 @@ class _ListCell extends StatefulWidget {
} }
class _ListCellState extends State<_ListCell> { class _ListCellState extends State<_ListCell> {
String _conditionToTagString(RedirectRuleCondition condition) { String _conditionToTagString(RedirectRuleCondition condition) {
switch (condition.type) { switch (condition.type) {
case RedirectRuleConditionType.DEVICE: case RedirectRuleConditionType.DEVICE:
@ -210,9 +215,9 @@ class _ListCellState extends State<_ListCell> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding(padding: EdgeInsets.only( return Padding(
left: 8, right: 8 padding: EdgeInsets.only(left: 8, right: 8),
), child: Container( child: Container(
padding: EdgeInsets.only(left: 8, right: 8, top: 16, bottom: 16), padding: EdgeInsets.only(left: 8, right: 8, top: 16, bottom: 16),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
@ -227,29 +232,33 @@ class _ListCellState extends State<_ListCell> {
children: [ children: [
Row( Row(
children: [ children: [
const Text("Long URL ", style: TextStyle(fontWeight: FontWeight.bold)), const Text("Long URL ",
style: TextStyle(fontWeight: FontWeight.bold)),
Text(widget.redirectRule.longUrl) Text(widget.redirectRule.longUrl)
], ],
), ),
Text("Conditions:", style: TextStyle(fontWeight: FontWeight.bold)), Text("Conditions:",
style: TextStyle(fontWeight: FontWeight.bold)),
Row( Row(
children: [ children: [
Expanded( Expanded(
child: Wrap( child: Wrap(
children: widget.redirectRule.conditions.map((condition) { children:
widget.redirectRule.conditions.map((condition) {
return Padding( return Padding(
padding: const EdgeInsets.only(right: 4, top: 4), padding: const EdgeInsets.only(right: 4, top: 4),
child: Container( child: Container(
padding: padding: const EdgeInsets.only(
const EdgeInsets.only(top: 4, bottom: 4, left: 12, right: 12), top: 4, bottom: 4, left: 12, right: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
color: MediaQuery.of(context).platformBrightness == Brightness.dark ? color:
Colors.grey[900] : Colors.grey[300], MediaQuery.of(context).platformBrightness ==
), Brightness.dark
child: Text( ? Colors.grey[900]
_conditionToTagString(condition) : Colors.grey[300],
), ),
child: Text(_conditionToTagString(condition)),
), ),
); );
}).toList(), }).toList(),
@ -260,14 +269,20 @@ class _ListCellState extends State<_ListCell> {
Wrap( Wrap(
children: [ children: [
IconButton( IconButton(
disabledColor: MediaQuery.of(context).platformBrightness disabledColor:
== Brightness.dark ? Colors.grey[700] : Colors.grey[400], MediaQuery.of(context).platformBrightness ==
Brightness.dark
? Colors.grey[700]
: Colors.grey[400],
onPressed: widget.moveUp, onPressed: widget.moveUp,
icon: Icon(Icons.arrow_upward), icon: Icon(Icons.arrow_upward),
), ),
IconButton( IconButton(
disabledColor: MediaQuery.of(context).platformBrightness disabledColor:
== Brightness.dark ? Colors.grey[700] : Colors.grey[400], MediaQuery.of(context).platformBrightness ==
Brightness.dark
? Colors.grey[700]
: Colors.grey[400],
onPressed: widget.moveDown, onPressed: widget.moveDown,
icon: Icon(Icons.arrow_downward), icon: Icon(Icons.arrow_downward),
), ),
@ -275,11 +290,9 @@ class _ListCellState extends State<_ListCell> {
onPressed: widget.delete, onPressed: widget.delete,
icon: Icon(Icons.delete, color: Colors.red), icon: Icon(Icons.delete, color: Colors.red),
) )
], ],
) )
], ],
) )));
));
} }
} }

View File

@ -130,7 +130,9 @@ class _URLDetailViewState extends State<URLDetailView> {
title: "Short URL", content: shortURL.shortUrl, isUrl: true), title: "Short URL", content: shortURL.shortUrl, isUrl: true),
_ListCell(title: "Long URL", content: shortURL.longUrl, isUrl: true), _ListCell(title: "Long URL", content: shortURL.longUrl, isUrl: true),
_ListCell(title: "Creation Date", content: shortURL.dateCreated), _ListCell(title: "Creation Date", content: shortURL.dateCreated),
_ListCell(title: "Redirect Rules", content: null, _ListCell(
title: "Redirect Rules",
content: null,
clickableDetailView: RedirectRulesDetailView(shortURL: shortURL)), clickableDetailView: RedirectRulesDetailView(shortURL: shortURL)),
const _ListCell(title: "Visits", content: ""), const _ListCell(title: "Visits", content: ""),
_ListCell( _ListCell(
@ -189,10 +191,8 @@ class _ListCellState extends State<_ListCell> {
child: GestureDetector( child: GestureDetector(
onTap: () async { onTap: () async {
if (widget.clickableDetailView != null) { if (widget.clickableDetailView != null) {
Navigator.of(context) Navigator.of(context).push(MaterialPageRoute(
.push(MaterialPageRoute( builder: (context) => widget.clickableDetailView!));
builder: (context) =>
widget.clickableDetailView!));
} else if (widget.content is String) { } else if (widget.content is String) {
Uri? parsedUrl = Uri.tryParse(widget.content); Uri? parsedUrl = Uri.tryParse(widget.content);
if (widget.isUrl && if (widget.isUrl &&