diff --git a/analysis_options.yaml b/analysis_options.yaml index d8d17f548..4ec45e6ab 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -9,6 +9,9 @@ # packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml +formatter: + trailing_commas: preserve + linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` diff --git a/lib/common/constants.dart b/lib/common/constants.dart index 81466c73c..93d5572ec 100644 --- a/lib/common/constants.dart +++ b/lib/common/constants.dart @@ -37,8 +37,9 @@ class Constants { static const String statisticsApp = '{"appId":1,"platform":3,"version":"8.43.0","abtest":""}'; - static final urlRegex = - RegExp(r'https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]'); + static final urlRegex = RegExp( + r'https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]', + ); static const goodsUrlPrefix = "https://gaoneng.bilibili.com/tetris"; @@ -49,7 +50,7 @@ class Constants { 'Anime4K_Upscale_CNN_x2_VL.glsl', 'Anime4K_AutoDownscalePre_x2.glsl', 'Anime4K_AutoDownscalePre_x4.glsl', - 'Anime4K_Upscale_CNN_x2_M.glsl' + 'Anime4K_Upscale_CNN_x2_M.glsl', ]; // 超分辨率滤镜 (轻量) @@ -60,225 +61,225 @@ class Constants { 'Anime4K_Upscale_CNN_x2_M.glsl', 'Anime4K_AutoDownscalePre_x2.glsl', 'Anime4K_AutoDownscalePre_x4.glsl', - 'Anime4K_Upscale_CNN_x2_S.glsl' + 'Anime4K_Upscale_CNN_x2_S.glsl', ]; //内容来自 https://passport.bilibili.com/web/generic/country/list static List> get internationalDialingPrefix => [ - {"id": 1, "cname": "中国大陆", "country_id": "86"}, - {"id": 5, "cname": "中国香港特别行政区", "country_id": "852"}, - {"id": 2, "cname": "中国澳门特别行政区", "country_id": "853"}, - {"id": 3, "cname": "中国台湾", "country_id": "886"}, - {"id": 4, "cname": "美国", "country_id": "1"}, - {"id": 6, "cname": "比利时", "country_id": "32"}, - {"id": 7, "cname": "澳大利亚", "country_id": "61"}, - {"id": 8, "cname": "法国", "country_id": "33"}, - {"id": 9, "cname": "加拿大", "country_id": "1"}, - {"id": 10, "cname": "日本", "country_id": "81"}, - {"id": 11, "cname": "新加坡", "country_id": "65"}, - {"id": 12, "cname": "韩国", "country_id": "82"}, - {"id": 13, "cname": "马来西亚", "country_id": "60"}, - {"id": 14, "cname": "英国", "country_id": "44"}, - {"id": 15, "cname": "意大利", "country_id": "39"}, - {"id": 16, "cname": "德国", "country_id": "49"}, - {"id": 18, "cname": "俄罗斯", "country_id": "7"}, - {"id": 19, "cname": "新西兰", "country_id": "64"}, //common:1-19 - {"id": 153, "cname": "瓦利斯群岛和富图纳群岛", "country_id": "1681"}, - {"id": 152, "cname": "葡萄牙", "country_id": "351"}, - {"id": 151, "cname": "帕劳", "country_id": "680"}, - {"id": 150, "cname": "诺福克岛", "country_id": "672"}, - {"id": 149, "cname": "挪威", "country_id": "47"}, - {"id": 148, "cname": "纽埃岛", "country_id": "683"}, - {"id": 147, "cname": "尼日利亚", "country_id": "234"}, - {"id": 146, "cname": "尼日尔", "country_id": "227"}, - {"id": 145, "cname": "尼加拉瓜", "country_id": "505"}, - {"id": 144, "cname": "尼泊尔", "country_id": "977"}, - {"id": 143, "cname": "瑙鲁", "country_id": "674"}, - {"id": 154, "cname": "格鲁吉亚", "country_id": "995"}, - {"id": 155, "cname": "瑞典", "country_id": "46"}, - {"id": 165, "cname": "沙特阿拉伯", "country_id": "966"}, - {"id": 164, "cname": "桑给巴尔岛", "country_id": "259"}, - {"id": 163, "cname": "塞舌尔共和国", "country_id": "248"}, - {"id": 162, "cname": "塞浦路斯", "country_id": "357"}, - {"id": 161, "cname": "塞内加尔", "country_id": "221"}, - {"id": 160, "cname": "塞拉利昂", "country_id": "232"}, - {"id": 159, "cname": "萨摩亚,东部", "country_id": "684"}, - {"id": 158, "cname": "萨摩亚,西部", "country_id": "685"}, - {"id": 157, "cname": "萨尔瓦多", "country_id": "503"}, - {"id": 156, "cname": "瑞士", "country_id": "41"}, - {"id": 166, "cname": "圣多美和普林西比", "country_id": "239"}, - {"id": 142, "cname": "塞尔维亚", "country_id": "381"}, - {"id": 141, "cname": "南非", "country_id": "27"}, - {"id": 128, "cname": "毛里塔尼亚", "country_id": "222"}, - {"id": 127, "cname": "毛里求斯", "country_id": "230"}, - {"id": 126, "cname": "马歇尔岛", "country_id": "692"}, - {"id": 125, "cname": "马提尼克岛", "country_id": "596"}, - {"id": 124, "cname": "马其顿", "country_id": "389"}, - {"id": 123, "cname": "马里亚纳岛", "country_id": "1670"}, - {"id": 122, "cname": "马里", "country_id": "223"}, - {"id": 121, "cname": "马拉维", "country_id": "265"}, - {"id": 120, "cname": "马耳他", "country_id": "356"}, - {"id": 119, "cname": "马尔代夫", "country_id": "960"}, - {"id": 129, "cname": "蒙古", "country_id": "976"}, - {"id": 130, "cname": "蒙特塞拉特岛", "country_id": "1664"}, - {"id": 140, "cname": "纳米比亚", "country_id": "264"}, - {"id": 139, "cname": "墨西哥", "country_id": "52"}, - {"id": 138, "cname": "莫桑比克", "country_id": "258"}, - {"id": 137, "cname": "摩纳哥", "country_id": "377"}, - {"id": 136, "cname": "摩洛哥", "country_id": "212"}, - {"id": 135, "cname": "摩尔多瓦", "country_id": "373"}, - {"id": 134, "cname": "缅甸", "country_id": "95"}, - {"id": 133, "cname": "密克罗尼西亚", "country_id": "691"}, - {"id": 132, "cname": "秘鲁", "country_id": "51"}, - {"id": 131, "cname": "孟加拉国", "country_id": "880"}, - {"id": 118, "cname": "马达加斯加", "country_id": "261"}, - {"id": 167, "cname": "圣卢西亚", "country_id": "1784"}, - {"id": 216, "cname": "智利", "country_id": "56"}, - {"id": 203, "cname": "牙买加", "country_id": "1876"}, - {"id": 202, "cname": "叙利亚", "country_id": "963"}, - {"id": 201, "cname": "匈牙利", "country_id": "36"}, - {"id": 200, "cname": "科特迪瓦", "country_id": "225"}, - {"id": 199, "cname": "希腊", "country_id": "30"}, - {"id": 198, "cname": "西班牙", "country_id": "34"}, - {"id": 197, "cname": "乌兹别克斯坦", "country_id": "998"}, - {"id": 196, "cname": "乌拉圭", "country_id": "598"}, - {"id": 195, "cname": "乌克兰", "country_id": "380"}, - {"id": 194, "cname": "乌干达", "country_id": "256"}, - {"id": 204, "cname": "亚美尼亚", "country_id": "374"}, - {"id": 205, "cname": "也门", "country_id": "967"}, - {"id": 215, "cname": "直布罗陀", "country_id": "350"}, - {"id": 214, "cname": "乍得", "country_id": "235"}, - {"id": 213, "cname": "赞比亚", "country_id": "260"}, - {"id": 212, "cname": "越南", "country_id": "84"}, - {"id": 211, "cname": "约旦", "country_id": "962"}, - {"id": 210, "cname": "印尼", "country_id": "62"}, - {"id": 209, "cname": "印度", "country_id": "91"}, - {"id": 208, "cname": "以色列", "country_id": "972"}, - {"id": 207, "cname": "伊朗", "country_id": "98"}, - {"id": 206, "cname": "伊拉克", "country_id": "964"}, - {"id": 193, "cname": "文莱", "country_id": "673"}, - {"id": 192, "cname": "委内瑞拉", "country_id": "58"}, - {"id": 191, "cname": "维珍群岛(英属)", "country_id": "1284"}, - {"id": 178, "cname": "泰国", "country_id": "66"}, - {"id": 177, "cname": "索马里", "country_id": "252"}, - {"id": 176, "cname": "所罗门群岛", "country_id": "677"}, - {"id": 175, "cname": "苏里南", "country_id": "597"}, - {"id": 174, "cname": "苏丹", "country_id": "249"}, - {"id": 173, "cname": "斯威士兰", "country_id": "268"}, - {"id": 172, "cname": "斯洛文尼亚", "country_id": "386"}, - {"id": 171, "cname": "斯洛伐克", "country_id": "421"}, - {"id": 170, "cname": "斯里兰卡", "country_id": "94"}, - {"id": 169, "cname": "圣皮埃尔和密克隆群岛", "country_id": "508"}, - {"id": 179, "cname": "坦桑尼亚", "country_id": "255"}, - {"id": 180, "cname": "汤加", "country_id": "676"}, - {"id": 190, "cname": "维珍群岛(美属)", "country_id": "1340"}, - {"id": 189, "cname": "瓦努阿图", "country_id": "678"}, - {"id": 188, "cname": "托克劳岛", "country_id": "690"}, - {"id": 187, "cname": "土库曼斯坦", "country_id": "993"}, - {"id": 186, "cname": "土耳其", "country_id": "90"}, - {"id": 185, "cname": "图瓦卢", "country_id": "688"}, - {"id": 184, "cname": "突尼斯", "country_id": "216"}, - {"id": 183, "cname": "阿森松岛", "country_id": "247"}, - {"id": 182, "cname": "特立尼达和多巴哥", "country_id": "1868"}, - {"id": 181, "cname": "特克斯和凯科斯", "country_id": "1649"}, - {"id": 168, "cname": "圣马力诺", "country_id": "378"}, - {"id": 67, "cname": "法属圭亚那", "country_id": "594"}, - {"id": 54, "cname": "不丹", "country_id": "975"}, - {"id": 53, "cname": "博茨瓦纳", "country_id": "267"}, - {"id": 52, "cname": "伯利兹", "country_id": "501"}, - {"id": 51, "cname": "玻利维亚", "country_id": "591"}, - {"id": 50, "cname": "波兰", "country_id": "48"}, - {"id": 49, "cname": "波黑", "country_id": "387"}, - {"id": 48, "cname": "波多黎各", "country_id": "1787"}, - {"id": 47, "cname": "冰岛", "country_id": "354"}, - {"id": 46, "cname": "贝宁", "country_id": "229"}, - {"id": 45, "cname": "保加利亚", "country_id": "359"}, - {"id": 55, "cname": "布基纳法索", "country_id": "226"}, - {"id": 56, "cname": "布隆迪", "country_id": "257"}, - {"id": 66, "cname": "法属波利尼西亚", "country_id": "689"}, - {"id": 65, "cname": "法罗岛", "country_id": "298"}, - {"id": 64, "cname": "厄立特里亚", "country_id": "291"}, - {"id": 63, "cname": "厄瓜多尔", "country_id": "593"}, - {"id": 62, "cname": "多米尼加代表", "country_id": "1809"}, - {"id": 61, "cname": "多米尼加", "country_id": "1767"}, - {"id": 60, "cname": "多哥", "country_id": "228"}, - {"id": 59, "cname": "迪戈加西亚岛", "country_id": "246"}, - {"id": 58, "cname": "丹麦", "country_id": "45"}, - {"id": 57, "cname": "赤道几内亚", "country_id": "240"}, - {"id": 44, "cname": "百慕大群岛", "country_id": "1441"}, - {"id": 43, "cname": "白俄罗斯", "country_id": "375"}, - {"id": 42, "cname": "巴西", "country_id": "55"}, - {"id": 29, "cname": "爱尔兰", "country_id": "353"}, - {"id": 28, "cname": "埃塞俄比亚", "country_id": "251"}, - {"id": 27, "cname": "埃及", "country_id": "20"}, - {"id": 26, "cname": "阿塞拜疆", "country_id": "994"}, - {"id": 25, "cname": "阿曼", "country_id": "968"}, - {"id": 24, "cname": "阿联酋", "country_id": "971"}, - {"id": 23, "cname": "阿根廷", "country_id": "54"}, - {"id": 22, "cname": "阿富汗", "country_id": "93"}, - {"id": 21, "cname": "阿尔及利亚", "country_id": "213"}, - {"id": 20, "cname": "阿尔巴尼亚", "country_id": "355"}, - {"id": 30, "cname": "爱沙尼亚", "country_id": "372"}, - {"id": 31, "cname": "安道尔", "country_id": "376"}, - {"id": 41, "cname": "巴拿马", "country_id": "507"}, - {"id": 40, "cname": "巴林", "country_id": "973"}, - {"id": 39, "cname": "巴拉圭", "country_id": "595"}, - {"id": 38, "cname": "巴基斯坦", "country_id": "92"}, - {"id": 37, "cname": "巴哈马群岛", "country_id": "1242"}, - {"id": 36, "cname": "巴布亚新几内亚", "country_id": "675"}, - {"id": 35, "cname": "巴巴多斯", "country_id": "1246"}, - {"id": 34, "cname": "奥地利", "country_id": "43"}, - {"id": 33, "cname": "安提瓜岛和巴布达", "country_id": "1268"}, - {"id": 32, "cname": "安哥拉", "country_id": "244"}, - {"id": 68, "cname": "非洲中部", "country_id": "236"}, - {"id": 117, "cname": "罗马尼亚", "country_id": "40"}, - {"id": 104, "cname": "科威特", "country_id": "965"}, - {"id": 103, "cname": "科摩罗", "country_id": "269"}, - {"id": 102, "cname": "开曼群岛", "country_id": "1345"}, - {"id": 101, "cname": "卡塔尔", "country_id": "974"}, - {"id": 100, "cname": "喀麦隆", "country_id": "237"}, - {"id": 99, "cname": "聚会岛", "country_id": "262"}, - {"id": 98, "cname": "津巴布韦", "country_id": "263"}, - {"id": 97, "cname": "捷克", "country_id": "420"}, - {"id": 96, "cname": "柬埔寨", "country_id": "855"}, - {"id": 95, "cname": "加蓬", "country_id": "241"}, - {"id": 105, "cname": "克罗地亚", "country_id": "385"}, - {"id": 106, "cname": "肯尼亚", "country_id": "254"}, - {"id": 116, "cname": "卢旺达", "country_id": "250"}, - {"id": 115, "cname": "卢森堡", "country_id": "352"}, - {"id": 114, "cname": "利比亚", "country_id": "218"}, - {"id": 113, "cname": "利比里亚", "country_id": "231"}, - {"id": 112, "cname": "立陶宛", "country_id": "370"}, - {"id": 111, "cname": "黎巴嫩", "country_id": "961"}, - {"id": 110, "cname": "老挝", "country_id": "856"}, - {"id": 109, "cname": "莱索托", "country_id": "266"}, - {"id": 108, "cname": "拉脱维亚", "country_id": "371"}, - {"id": 107, "cname": "库克岛", "country_id": "682"}, - {"id": 94, "cname": "加纳", "country_id": "233"}, - {"id": 93, "cname": "几内亚比绍", "country_id": "245"}, - {"id": 92, "cname": "几内亚", "country_id": "224"}, - {"id": 79, "cname": "格林纳达", "country_id": "1473"}, - {"id": 78, "cname": "哥斯达黎加", "country_id": "506"}, - {"id": 77, "cname": "哥伦比亚", "country_id": "57"}, - {"id": 76, "cname": "刚果(金)", "country_id": "243"}, - {"id": 75, "cname": "刚果", "country_id": "242"}, - {"id": 74, "cname": "冈比亚", "country_id": "220"}, - {"id": 73, "cname": "福克兰岛", "country_id": "500"}, - {"id": 72, "cname": "佛得角", "country_id": "238"}, - {"id": 71, "cname": "芬兰", "country_id": "358"}, - {"id": 70, "cname": "斐济", "country_id": "679"}, - {"id": 80, "cname": "格陵兰岛", "country_id": "299"}, - {"id": 81, "cname": "古巴", "country_id": "53"}, - {"id": 91, "cname": "吉尔吉斯斯坦", "country_id": "996"}, - {"id": 90, "cname": "吉布提", "country_id": "253"}, - {"id": 89, "cname": "基里巴斯", "country_id": "686"}, - {"id": 88, "cname": "维克岛", "country_id": "1808"}, - {"id": 87, "cname": "洪都拉斯", "country_id": "504"}, - {"id": 86, "cname": "荷兰", "country_id": "31"}, - {"id": 85, "cname": "朝鲜", "country_id": "850"}, - {"id": 84, "cname": "海地", "country_id": "509"}, - {"id": 83, "cname": "关岛", "country_id": "1671"}, - {"id": 82, "cname": "瓜德罗普岛", "country_id": "590"}, - {"id": 69, "cname": "菲律宾", "country_id": "63"} - ]; + {"id": 1, "cname": "中国大陆", "country_id": "86"}, + {"id": 5, "cname": "中国香港特别行政区", "country_id": "852"}, + {"id": 2, "cname": "中国澳门特别行政区", "country_id": "853"}, + {"id": 3, "cname": "中国台湾", "country_id": "886"}, + {"id": 4, "cname": "美国", "country_id": "1"}, + {"id": 6, "cname": "比利时", "country_id": "32"}, + {"id": 7, "cname": "澳大利亚", "country_id": "61"}, + {"id": 8, "cname": "法国", "country_id": "33"}, + {"id": 9, "cname": "加拿大", "country_id": "1"}, + {"id": 10, "cname": "日本", "country_id": "81"}, + {"id": 11, "cname": "新加坡", "country_id": "65"}, + {"id": 12, "cname": "韩国", "country_id": "82"}, + {"id": 13, "cname": "马来西亚", "country_id": "60"}, + {"id": 14, "cname": "英国", "country_id": "44"}, + {"id": 15, "cname": "意大利", "country_id": "39"}, + {"id": 16, "cname": "德国", "country_id": "49"}, + {"id": 18, "cname": "俄罗斯", "country_id": "7"}, + {"id": 19, "cname": "新西兰", "country_id": "64"}, //common:1-19 + {"id": 153, "cname": "瓦利斯群岛和富图纳群岛", "country_id": "1681"}, + {"id": 152, "cname": "葡萄牙", "country_id": "351"}, + {"id": 151, "cname": "帕劳", "country_id": "680"}, + {"id": 150, "cname": "诺福克岛", "country_id": "672"}, + {"id": 149, "cname": "挪威", "country_id": "47"}, + {"id": 148, "cname": "纽埃岛", "country_id": "683"}, + {"id": 147, "cname": "尼日利亚", "country_id": "234"}, + {"id": 146, "cname": "尼日尔", "country_id": "227"}, + {"id": 145, "cname": "尼加拉瓜", "country_id": "505"}, + {"id": 144, "cname": "尼泊尔", "country_id": "977"}, + {"id": 143, "cname": "瑙鲁", "country_id": "674"}, + {"id": 154, "cname": "格鲁吉亚", "country_id": "995"}, + {"id": 155, "cname": "瑞典", "country_id": "46"}, + {"id": 165, "cname": "沙特阿拉伯", "country_id": "966"}, + {"id": 164, "cname": "桑给巴尔岛", "country_id": "259"}, + {"id": 163, "cname": "塞舌尔共和国", "country_id": "248"}, + {"id": 162, "cname": "塞浦路斯", "country_id": "357"}, + {"id": 161, "cname": "塞内加尔", "country_id": "221"}, + {"id": 160, "cname": "塞拉利昂", "country_id": "232"}, + {"id": 159, "cname": "萨摩亚,东部", "country_id": "684"}, + {"id": 158, "cname": "萨摩亚,西部", "country_id": "685"}, + {"id": 157, "cname": "萨尔瓦多", "country_id": "503"}, + {"id": 156, "cname": "瑞士", "country_id": "41"}, + {"id": 166, "cname": "圣多美和普林西比", "country_id": "239"}, + {"id": 142, "cname": "塞尔维亚", "country_id": "381"}, + {"id": 141, "cname": "南非", "country_id": "27"}, + {"id": 128, "cname": "毛里塔尼亚", "country_id": "222"}, + {"id": 127, "cname": "毛里求斯", "country_id": "230"}, + {"id": 126, "cname": "马歇尔岛", "country_id": "692"}, + {"id": 125, "cname": "马提尼克岛", "country_id": "596"}, + {"id": 124, "cname": "马其顿", "country_id": "389"}, + {"id": 123, "cname": "马里亚纳岛", "country_id": "1670"}, + {"id": 122, "cname": "马里", "country_id": "223"}, + {"id": 121, "cname": "马拉维", "country_id": "265"}, + {"id": 120, "cname": "马耳他", "country_id": "356"}, + {"id": 119, "cname": "马尔代夫", "country_id": "960"}, + {"id": 129, "cname": "蒙古", "country_id": "976"}, + {"id": 130, "cname": "蒙特塞拉特岛", "country_id": "1664"}, + {"id": 140, "cname": "纳米比亚", "country_id": "264"}, + {"id": 139, "cname": "墨西哥", "country_id": "52"}, + {"id": 138, "cname": "莫桑比克", "country_id": "258"}, + {"id": 137, "cname": "摩纳哥", "country_id": "377"}, + {"id": 136, "cname": "摩洛哥", "country_id": "212"}, + {"id": 135, "cname": "摩尔多瓦", "country_id": "373"}, + {"id": 134, "cname": "缅甸", "country_id": "95"}, + {"id": 133, "cname": "密克罗尼西亚", "country_id": "691"}, + {"id": 132, "cname": "秘鲁", "country_id": "51"}, + {"id": 131, "cname": "孟加拉国", "country_id": "880"}, + {"id": 118, "cname": "马达加斯加", "country_id": "261"}, + {"id": 167, "cname": "圣卢西亚", "country_id": "1784"}, + {"id": 216, "cname": "智利", "country_id": "56"}, + {"id": 203, "cname": "牙买加", "country_id": "1876"}, + {"id": 202, "cname": "叙利亚", "country_id": "963"}, + {"id": 201, "cname": "匈牙利", "country_id": "36"}, + {"id": 200, "cname": "科特迪瓦", "country_id": "225"}, + {"id": 199, "cname": "希腊", "country_id": "30"}, + {"id": 198, "cname": "西班牙", "country_id": "34"}, + {"id": 197, "cname": "乌兹别克斯坦", "country_id": "998"}, + {"id": 196, "cname": "乌拉圭", "country_id": "598"}, + {"id": 195, "cname": "乌克兰", "country_id": "380"}, + {"id": 194, "cname": "乌干达", "country_id": "256"}, + {"id": 204, "cname": "亚美尼亚", "country_id": "374"}, + {"id": 205, "cname": "也门", "country_id": "967"}, + {"id": 215, "cname": "直布罗陀", "country_id": "350"}, + {"id": 214, "cname": "乍得", "country_id": "235"}, + {"id": 213, "cname": "赞比亚", "country_id": "260"}, + {"id": 212, "cname": "越南", "country_id": "84"}, + {"id": 211, "cname": "约旦", "country_id": "962"}, + {"id": 210, "cname": "印尼", "country_id": "62"}, + {"id": 209, "cname": "印度", "country_id": "91"}, + {"id": 208, "cname": "以色列", "country_id": "972"}, + {"id": 207, "cname": "伊朗", "country_id": "98"}, + {"id": 206, "cname": "伊拉克", "country_id": "964"}, + {"id": 193, "cname": "文莱", "country_id": "673"}, + {"id": 192, "cname": "委内瑞拉", "country_id": "58"}, + {"id": 191, "cname": "维珍群岛(英属)", "country_id": "1284"}, + {"id": 178, "cname": "泰国", "country_id": "66"}, + {"id": 177, "cname": "索马里", "country_id": "252"}, + {"id": 176, "cname": "所罗门群岛", "country_id": "677"}, + {"id": 175, "cname": "苏里南", "country_id": "597"}, + {"id": 174, "cname": "苏丹", "country_id": "249"}, + {"id": 173, "cname": "斯威士兰", "country_id": "268"}, + {"id": 172, "cname": "斯洛文尼亚", "country_id": "386"}, + {"id": 171, "cname": "斯洛伐克", "country_id": "421"}, + {"id": 170, "cname": "斯里兰卡", "country_id": "94"}, + {"id": 169, "cname": "圣皮埃尔和密克隆群岛", "country_id": "508"}, + {"id": 179, "cname": "坦桑尼亚", "country_id": "255"}, + {"id": 180, "cname": "汤加", "country_id": "676"}, + {"id": 190, "cname": "维珍群岛(美属)", "country_id": "1340"}, + {"id": 189, "cname": "瓦努阿图", "country_id": "678"}, + {"id": 188, "cname": "托克劳岛", "country_id": "690"}, + {"id": 187, "cname": "土库曼斯坦", "country_id": "993"}, + {"id": 186, "cname": "土耳其", "country_id": "90"}, + {"id": 185, "cname": "图瓦卢", "country_id": "688"}, + {"id": 184, "cname": "突尼斯", "country_id": "216"}, + {"id": 183, "cname": "阿森松岛", "country_id": "247"}, + {"id": 182, "cname": "特立尼达和多巴哥", "country_id": "1868"}, + {"id": 181, "cname": "特克斯和凯科斯", "country_id": "1649"}, + {"id": 168, "cname": "圣马力诺", "country_id": "378"}, + {"id": 67, "cname": "法属圭亚那", "country_id": "594"}, + {"id": 54, "cname": "不丹", "country_id": "975"}, + {"id": 53, "cname": "博茨瓦纳", "country_id": "267"}, + {"id": 52, "cname": "伯利兹", "country_id": "501"}, + {"id": 51, "cname": "玻利维亚", "country_id": "591"}, + {"id": 50, "cname": "波兰", "country_id": "48"}, + {"id": 49, "cname": "波黑", "country_id": "387"}, + {"id": 48, "cname": "波多黎各", "country_id": "1787"}, + {"id": 47, "cname": "冰岛", "country_id": "354"}, + {"id": 46, "cname": "贝宁", "country_id": "229"}, + {"id": 45, "cname": "保加利亚", "country_id": "359"}, + {"id": 55, "cname": "布基纳法索", "country_id": "226"}, + {"id": 56, "cname": "布隆迪", "country_id": "257"}, + {"id": 66, "cname": "法属波利尼西亚", "country_id": "689"}, + {"id": 65, "cname": "法罗岛", "country_id": "298"}, + {"id": 64, "cname": "厄立特里亚", "country_id": "291"}, + {"id": 63, "cname": "厄瓜多尔", "country_id": "593"}, + {"id": 62, "cname": "多米尼加代表", "country_id": "1809"}, + {"id": 61, "cname": "多米尼加", "country_id": "1767"}, + {"id": 60, "cname": "多哥", "country_id": "228"}, + {"id": 59, "cname": "迪戈加西亚岛", "country_id": "246"}, + {"id": 58, "cname": "丹麦", "country_id": "45"}, + {"id": 57, "cname": "赤道几内亚", "country_id": "240"}, + {"id": 44, "cname": "百慕大群岛", "country_id": "1441"}, + {"id": 43, "cname": "白俄罗斯", "country_id": "375"}, + {"id": 42, "cname": "巴西", "country_id": "55"}, + {"id": 29, "cname": "爱尔兰", "country_id": "353"}, + {"id": 28, "cname": "埃塞俄比亚", "country_id": "251"}, + {"id": 27, "cname": "埃及", "country_id": "20"}, + {"id": 26, "cname": "阿塞拜疆", "country_id": "994"}, + {"id": 25, "cname": "阿曼", "country_id": "968"}, + {"id": 24, "cname": "阿联酋", "country_id": "971"}, + {"id": 23, "cname": "阿根廷", "country_id": "54"}, + {"id": 22, "cname": "阿富汗", "country_id": "93"}, + {"id": 21, "cname": "阿尔及利亚", "country_id": "213"}, + {"id": 20, "cname": "阿尔巴尼亚", "country_id": "355"}, + {"id": 30, "cname": "爱沙尼亚", "country_id": "372"}, + {"id": 31, "cname": "安道尔", "country_id": "376"}, + {"id": 41, "cname": "巴拿马", "country_id": "507"}, + {"id": 40, "cname": "巴林", "country_id": "973"}, + {"id": 39, "cname": "巴拉圭", "country_id": "595"}, + {"id": 38, "cname": "巴基斯坦", "country_id": "92"}, + {"id": 37, "cname": "巴哈马群岛", "country_id": "1242"}, + {"id": 36, "cname": "巴布亚新几内亚", "country_id": "675"}, + {"id": 35, "cname": "巴巴多斯", "country_id": "1246"}, + {"id": 34, "cname": "奥地利", "country_id": "43"}, + {"id": 33, "cname": "安提瓜岛和巴布达", "country_id": "1268"}, + {"id": 32, "cname": "安哥拉", "country_id": "244"}, + {"id": 68, "cname": "非洲中部", "country_id": "236"}, + {"id": 117, "cname": "罗马尼亚", "country_id": "40"}, + {"id": 104, "cname": "科威特", "country_id": "965"}, + {"id": 103, "cname": "科摩罗", "country_id": "269"}, + {"id": 102, "cname": "开曼群岛", "country_id": "1345"}, + {"id": 101, "cname": "卡塔尔", "country_id": "974"}, + {"id": 100, "cname": "喀麦隆", "country_id": "237"}, + {"id": 99, "cname": "聚会岛", "country_id": "262"}, + {"id": 98, "cname": "津巴布韦", "country_id": "263"}, + {"id": 97, "cname": "捷克", "country_id": "420"}, + {"id": 96, "cname": "柬埔寨", "country_id": "855"}, + {"id": 95, "cname": "加蓬", "country_id": "241"}, + {"id": 105, "cname": "克罗地亚", "country_id": "385"}, + {"id": 106, "cname": "肯尼亚", "country_id": "254"}, + {"id": 116, "cname": "卢旺达", "country_id": "250"}, + {"id": 115, "cname": "卢森堡", "country_id": "352"}, + {"id": 114, "cname": "利比亚", "country_id": "218"}, + {"id": 113, "cname": "利比里亚", "country_id": "231"}, + {"id": 112, "cname": "立陶宛", "country_id": "370"}, + {"id": 111, "cname": "黎巴嫩", "country_id": "961"}, + {"id": 110, "cname": "老挝", "country_id": "856"}, + {"id": 109, "cname": "莱索托", "country_id": "266"}, + {"id": 108, "cname": "拉脱维亚", "country_id": "371"}, + {"id": 107, "cname": "库克岛", "country_id": "682"}, + {"id": 94, "cname": "加纳", "country_id": "233"}, + {"id": 93, "cname": "几内亚比绍", "country_id": "245"}, + {"id": 92, "cname": "几内亚", "country_id": "224"}, + {"id": 79, "cname": "格林纳达", "country_id": "1473"}, + {"id": 78, "cname": "哥斯达黎加", "country_id": "506"}, + {"id": 77, "cname": "哥伦比亚", "country_id": "57"}, + {"id": 76, "cname": "刚果(金)", "country_id": "243"}, + {"id": 75, "cname": "刚果", "country_id": "242"}, + {"id": 74, "cname": "冈比亚", "country_id": "220"}, + {"id": 73, "cname": "福克兰岛", "country_id": "500"}, + {"id": 72, "cname": "佛得角", "country_id": "238"}, + {"id": 71, "cname": "芬兰", "country_id": "358"}, + {"id": 70, "cname": "斐济", "country_id": "679"}, + {"id": 80, "cname": "格陵兰岛", "country_id": "299"}, + {"id": 81, "cname": "古巴", "country_id": "53"}, + {"id": 91, "cname": "吉尔吉斯斯坦", "country_id": "996"}, + {"id": 90, "cname": "吉布提", "country_id": "253"}, + {"id": 89, "cname": "基里巴斯", "country_id": "686"}, + {"id": 88, "cname": "维克岛", "country_id": "1808"}, + {"id": 87, "cname": "洪都拉斯", "country_id": "504"}, + {"id": 86, "cname": "荷兰", "country_id": "31"}, + {"id": 85, "cname": "朝鲜", "country_id": "850"}, + {"id": 84, "cname": "海地", "country_id": "509"}, + {"id": 83, "cname": "关岛", "country_id": "1671"}, + {"id": 82, "cname": "瓜德罗普岛", "country_id": "590"}, + {"id": 69, "cname": "菲律宾", "country_id": "63"}, + ]; } diff --git a/lib/common/skeleton/dynamic_card.dart b/lib/common/skeleton/dynamic_card.dart index 4c43e453a..94063e3d2 100644 --- a/lib/common/skeleton/dynamic_card.dart +++ b/lib/common/skeleton/dynamic_card.dart @@ -47,7 +47,7 @@ class DynamicCardSkeleton extends StatelessWidget { height: 11, ), ], - ) + ), ], ), Container( @@ -102,19 +102,20 @@ class DynamicCardSkeleton extends StatelessWidget { ), style: TextButton.styleFrom( padding: const EdgeInsets.fromLTRB(15, 0, 15, 0), - foregroundColor: - theme.colorScheme.outline.withValues(alpha: 0.2), + foregroundColor: theme.colorScheme.outline.withValues( + alpha: 0.2, + ), ), label: Text( i == 0 ? '转发' : i == 1 - ? '评论' - : '点赞', + ? '评论' + : '点赞', ), - ) + ), ], - ) + ), ], ), ), diff --git a/lib/common/skeleton/media_bangumi.dart b/lib/common/skeleton/media_bangumi.dart index 681e3524b..eb26f30c2 100644 --- a/lib/common/skeleton/media_bangumi.dart +++ b/lib/common/skeleton/media_bangumi.dart @@ -16,7 +16,11 @@ class _MediaPgcSkeletonState extends State { return Skeleton( child: Padding( padding: const EdgeInsets.fromLTRB( - StyleString.safeSpace, 7, StyleString.safeSpace, 7), + StyleString.safeSpace, + 7, + StyleString.safeSpace, + 7, + ), child: Row( children: [ Container( @@ -62,8 +66,9 @@ class _MediaPgcSkeletonState extends State { width: 90, height: 35, decoration: BoxDecoration( - borderRadius: - const BorderRadius.all(Radius.circular(20)), + borderRadius: const BorderRadius.all( + Radius.circular(20), + ), color: bgColor, ), ), diff --git a/lib/common/skeleton/skeleton.dart b/lib/common/skeleton/skeleton.dart index 40f6560f9..874652c89 100644 --- a/lib/common/skeleton/skeleton.dart +++ b/lib/common/skeleton/skeleton.dart @@ -74,14 +74,14 @@ class ShimmerState extends State with SingleTickerProviderStateMixin { } LinearGradient get gradient => LinearGradient( - colors: widget.linearGradient.colors, - stops: widget.linearGradient.stops, - begin: widget.linearGradient.begin, - end: widget.linearGradient.end, - transform: _SlidingGradientTransform( - slidePercent: _shimmerController.value, - ), - ); + colors: widget.linearGradient.colors, + stops: widget.linearGradient.stops, + begin: widget.linearGradient.begin, + end: widget.linearGradient.end, + transform: _SlidingGradientTransform( + slidePercent: _shimmerController.value, + ), + ); bool get isSized => (context.findRenderObject() as RenderBox?)?.hasSize ?? false; diff --git a/lib/common/skeleton/space_opus.dart b/lib/common/skeleton/space_opus.dart index b07062643..e62e15c42 100644 --- a/lib/common/skeleton/space_opus.dart +++ b/lib/common/skeleton/space_opus.dart @@ -20,7 +20,8 @@ class SpaceOpusSkeleton extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - height: (0.68 + 0.82 * Utils.random.nextDouble()) * + height: + (0.68 + 0.82 * Utils.random.nextDouble()) * constraints.maxWidth, color: surface, ), @@ -33,8 +34,11 @@ class SpaceOpusSkeleton extends StatelessWidget { Container( height: 10, color: surface, - margin: - const EdgeInsets.only(left: 10, right: 10, bottom: 10), + margin: const EdgeInsets.only( + left: 10, + right: 10, + bottom: 10, + ), width: constraints.maxWidth, ), ], diff --git a/lib/common/skeleton/video_card_h.dart b/lib/common/skeleton/video_card_h.dart index 90a2a143f..7210ef4c0 100644 --- a/lib/common/skeleton/video_card_h.dart +++ b/lib/common/skeleton/video_card_h.dart @@ -68,7 +68,7 @@ class VideoCardHSkeleton extends StatelessWidget { height: 13, ), ], - ) + ), ], ), ), diff --git a/lib/common/skeleton/video_reply.dart b/lib/common/skeleton/video_reply.dart index bf0ed16d6..e04088c0e 100644 --- a/lib/common/skeleton/video_reply.dart +++ b/lib/common/skeleton/video_reply.dart @@ -26,14 +26,18 @@ class VideoReplySkeleton extends StatelessWidget { width: 80, height: 13, color: bgColor, - ) + ), ], ), ), Container( width: double.infinity, - margin: - const EdgeInsets.only(top: 4, left: 57, right: 6, bottom: 6), + margin: const EdgeInsets.only( + top: 4, + left: 57, + right: 6, + bottom: 6, + ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -71,9 +75,9 @@ class VideoReplySkeleton extends StatelessWidget { margin: const EdgeInsets.only(bottom: 4), color: bgColor, ), - const SizedBox(width: 8) + const SizedBox(width: 8), ], - ) + ), ], ), ), diff --git a/lib/common/widgets/badge.dart b/lib/common/widgets/badge.dart index 3a7c8f836..1936dea03 100644 --- a/lib/common/widgets/badge.dart +++ b/lib/common/widgets/badge.dart @@ -75,13 +75,16 @@ class PBadge extends StatelessWidget { bgColor = Colors.transparent; borderColor = theme.secondary; case PBadgeType.free: - bgColor = - Get.isDarkMode ? const Color(0xFFD66011) : const Color(0xFFFF7F24); + bgColor = Get.isDarkMode + ? const Color(0xFFD66011) + : const Color(0xFFFF7F24); color = Colors.white; } - late EdgeInsets paddingStyle = - const EdgeInsets.symmetric(vertical: 2, horizontal: 3); + late EdgeInsets paddingStyle = const EdgeInsets.symmetric( + vertical: 2, + horizontal: 3, + ); BorderRadius br = size == PBadgeSize.small ? const BorderRadius.all(Radius.circular(3)) : const BorderRadius.all(Radius.circular(4)); diff --git a/lib/common/widgets/color_palette.dart b/lib/common/widgets/color_palette.dart index 49c3aff30..5008e67ac 100644 --- a/lib/common/widgets/color_palette.dart +++ b/lib/common/widgets/color_palette.dart @@ -21,11 +21,11 @@ class ColorPalette extends StatelessWidget { final primaryContainer = Color(Hct.from(hct.hue, 30.0, 50.0).toInt()); final checkbox = Color(Hct.from(hct.hue, 30.0, 40.0).toInt()); Widget coloredBox(Color color) => Expanded( - child: ColoredBox( - color: color, - child: const SizedBox.expand(), - ), - ); + child: ColoredBox( + color: color, + child: const SizedBox.expand(), + ), + ); Widget child = ClipOval( child: Column( children: [ diff --git a/lib/common/widgets/custom_sliver_persistent_header_delegate.dart b/lib/common/widgets/custom_sliver_persistent_header_delegate.dart index b010f5b56..993f69b90 100644 --- a/lib/common/widgets/custom_sliver_persistent_header_delegate.dart +++ b/lib/common/widgets/custom_sliver_persistent_header_delegate.dart @@ -7,8 +7,8 @@ class CustomSliverPersistentHeaderDelegate required this.bgColor, double extent = 45, this.needRebuild, - }) : _minExtent = extent, - _maxExtent = extent; + }) : _minExtent = extent, + _maxExtent = extent; final double _minExtent; final double _maxExtent; final Widget child; @@ -17,7 +17,10 @@ class CustomSliverPersistentHeaderDelegate @override Widget build( - BuildContext context, double shrinkOffset, bool overlapsContent) { + BuildContext context, + double shrinkOffset, + bool overlapsContent, + ) { //创建child子组件 //shrinkOffset:child偏移值minExtent~maxExtent //overlapsContent:SliverPersistentHeader覆盖其他子组件返回true,否则返回false diff --git a/lib/common/widgets/custom_toast.dart b/lib/common/widgets/custom_toast.dart index 196e32c7b..7c6a64b40 100644 --- a/lib/common/widgets/custom_toast.dart +++ b/lib/common/widgets/custom_toast.dart @@ -12,12 +12,14 @@ class CustomToast extends StatelessWidget { Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); return Container( - margin: - EdgeInsets.only(bottom: MediaQuery.paddingOf(context).bottom + 30), + margin: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 30, + ), padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10), decoration: BoxDecoration( - color: - theme.colorScheme.primaryContainer.withValues(alpha: toastOpacity), + color: theme.colorScheme.primaryContainer.withValues( + alpha: toastOpacity, + ), borderRadius: const BorderRadius.all(Radius.circular(20)), ), child: Text( @@ -47,19 +49,22 @@ class LoadingWidget extends StatelessWidget { color: theme.dialogBackgroundColor, borderRadius: const BorderRadius.all(Radius.circular(15)), ), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - //loading animation - CircularProgressIndicator( - strokeWidth: 3, - valueColor: AlwaysStoppedAnimation(onSurfaceVariant), - ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + //loading animation + CircularProgressIndicator( + strokeWidth: 3, + valueColor: AlwaysStoppedAnimation(onSurfaceVariant), + ), - //msg - Container( - margin: const EdgeInsets.only(top: 20), - child: Text(msg, style: TextStyle(color: onSurfaceVariant)), - ), - ]), + //msg + Container( + margin: const EdgeInsets.only(top: 20), + child: Text(msg, style: TextStyle(color: onSurfaceVariant)), + ), + ], + ), ); } } diff --git a/lib/common/widgets/custom_tooltip.dart b/lib/common/widgets/custom_tooltip.dart index cf374cf3a..e08cde428 100644 --- a/lib/common/widgets/custom_tooltip.dart +++ b/lib/common/widgets/custom_tooltip.dart @@ -108,8 +108,10 @@ class CustomTooltipState extends State } Widget _buildCustomTooltipOverlay(BuildContext context) { - final OverlayState overlayState = - Overlay.of(context, debugRequiredFor: widget); + final OverlayState overlayState = Overlay.of( + context, + debugRequiredFor: widget, + ); final RenderBox box = this.context.findRenderObject()! as RenderBox; final Offset target = box.localToGlobal( box.size.center(Offset.zero), @@ -238,8 +240,10 @@ class _CustomMultiTooltipPositionDelegate extends MultiChildLayoutDelegate { } if (hasChild('overlay')) { - final overlaySize = - layoutChild('overlay', BoxConstraints.loose(size)); + final overlaySize = layoutChild( + 'overlay', + BoxConstraints.loose(size), + ); Offset offset = positionDependentBox( type: type, size: size, @@ -268,8 +272,10 @@ class _CustomMultiTooltipPositionDelegate extends MultiChildLayoutDelegate { } if (hasChild('overlay')) { - final overlaySize = - layoutChild('overlay', BoxConstraints.loose(size)); + final overlaySize = layoutChild( + 'overlay', + BoxConstraints.loose(size), + ); Offset offset = positionDependentBox( type: type, size: size, @@ -353,8 +359,9 @@ Offset positionDependentBox({ target.dy + verticalOffset + childSize.height <= size.height - margin; final bool fitsAbove = target.dy - verticalOffset - childSize.height >= margin; - final bool tooltipBelow = - fitsAbove == fitsBelow ? preferBelow : fitsBelow; + final bool tooltipBelow = fitsAbove == fitsBelow + ? preferBelow + : fitsBelow; final double y; if (tooltipBelow) { y = math.min(target.dy + verticalOffset, size.height - margin); @@ -367,12 +374,17 @@ Offset positionDependentBox({ // child. ? flexibleSpace / 2.0 : clampDouble( - target.dx - childSize.width / 2, margin, flexibleSpace - margin); + target.dx - childSize.width / 2, + margin, + flexibleSpace - margin, + ); return Offset(x, y); case TooltipType.right: final double dy = math.max(margin, target.dy - childSize.height / 2); final double dx = math.min( - target.dx + horizontslOffset, size.width - childSize.width - margin); + target.dx + horizontslOffset, + size.width - childSize.width - margin, + ); return Offset(dx, dy); } } diff --git a/lib/common/widgets/dialog/dialog.dart b/lib/common/widgets/dialog/dialog.dart index bc89da12d..99823fd61 100644 --- a/lib/common/widgets/dialog/dialog.dart +++ b/lib/common/widgets/dialog/dialog.dart @@ -15,8 +15,8 @@ void showConfirmDialog({ content: content is String ? Text(content) : content is Widget - ? content - : null, + ? content + : null, actions: [ TextButton( onPressed: Get.back, @@ -99,7 +99,7 @@ void showPgcFollowDialog({ Get.back(); onUpdateStatus(-1); }, - ) + ), ], ), ), diff --git a/lib/common/widgets/dialog/report.dart b/lib/common/widgets/dialog/report.dart index 46c7475aa..6da40b676 100644 --- a/lib/common/widgets/dialog/report.dart +++ b/lib/common/widgets/dialog/report.dart @@ -8,7 +8,7 @@ void autoWrapReportDialog( BuildContext context, Map> options, Future Function(int reasonType, String? reasonDesc, bool banUid) - onSuccess, + onSuccess, ) { int? reasonType; String? reasonDesc; @@ -22,8 +22,11 @@ void autoWrapReportDialog( title: const Text('举报'), titlePadding: const EdgeInsets.only(left: 22, top: 16, right: 22), contentPadding: const EdgeInsets.symmetric(vertical: 5), - actionsPadding: - const EdgeInsets.only(left: 16, right: 16, bottom: 10), + actionsPadding: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 10, + ), content: Form( key: key, child: Column( @@ -56,7 +59,8 @@ void autoWrapReportDialog( ), if (reasonType == 0) ReasonField( - onChanged: (value) => reasonDesc = value), + onChanged: (value) => reasonDesc = value, + ), ], ), ), @@ -65,7 +69,9 @@ void autoWrapReportDialog( Padding( padding: const EdgeInsets.only(left: 14, top: 6), child: CheckBoxText( - text: '拉黑该用户', onChanged: (value) => banUid = value), + text: '拉黑该用户', + onChanged: (value) => banUid = value, + ), ), ], ), @@ -211,33 +217,33 @@ class _CheckBoxTextState extends State { class ReportOptions { // from https://s1.hdslb.com/bfs/seed/jinkela/comment-h5/static/js/605.chunks.js static Map> get commentReport => const { - '违反法律法规': {9: '违法违规', 2: '色情', 10: '低俗', 12: '赌博诈骗', 23: '违法信息外链'}, - '谣言类不实信息': {19: '涉政谣言', 22: '虚假不实信息', 20: '涉社会事件谣言'}, - '侵犯个人权益': {7: '人身攻击', 15: '侵犯隐私'}, - '有害社区环境': { - 1: '垃圾广告', - 4: '引战', - 5: '剧透', - 3: '刷屏', - 8: '视频不相关', - 18: '违规抽奖', - 17: '青少年不良信息', - }, - '其他': {0: '其他'}, - }; + '违反法律法规': {9: '违法违规', 2: '色情', 10: '低俗', 12: '赌博诈骗', 23: '违法信息外链'}, + '谣言类不实信息': {19: '涉政谣言', 22: '虚假不实信息', 20: '涉社会事件谣言'}, + '侵犯个人权益': {7: '人身攻击', 15: '侵犯隐私'}, + '有害社区环境': { + 1: '垃圾广告', + 4: '引战', + 5: '剧透', + 3: '刷屏', + 8: '视频不相关', + 18: '违规抽奖', + 17: '青少年不良信息', + }, + '其他': {0: '其他'}, + }; static Map> get dynamicReport => const { - '': { - 4: '垃圾广告', - 8: '引战', - 1: '色情', - 5: '人身攻击', - 3: '违法信息', - 9: '涉政谣言', - 10: '涉社会事件谣言', - 12: '虚假不实信息', - 13: '违法信息外链', - 0: '其他', - }, - }; + '': { + 4: '垃圾广告', + 8: '引战', + 1: '色情', + 5: '人身攻击', + 3: '违法信息', + 9: '涉政谣言', + 10: '涉社会事件谣言', + 12: '虚假不实信息', + 13: '违法信息外链', + 0: '其他', + }, + }; } diff --git a/lib/common/widgets/disabled_icon.dart b/lib/common/widgets/disabled_icon.dart index b9991c7a5..f51e95ffb 100644 --- a/lib/common/widgets/disabled_icon.dart +++ b/lib/common/widgets/disabled_icon.dart @@ -14,9 +14,9 @@ class DisabledIcon extends SingleChildRenderObjectWidget { this.color, double? lineLengthScale, StrokeCap? strokeCap, - }) : lineLengthScale = lineLengthScale ?? 0.9, - strokeCap = strokeCap ?? StrokeCap.butt, - super(child: child); + }) : lineLengthScale = lineLengthScale ?? 0.9, + strokeCap = strokeCap ?? StrokeCap.butt, + super(child: child); @override RenderObject createRenderObject(BuildContext context) { @@ -60,16 +60,17 @@ class RenderMaskedIcon extends RenderProxyBox { // ); final path = Path.combine( - PathOperation.union, - Path() // bottom - ..moveTo(rect.left, rect.bottom) - ..lineTo(rect.left, rect.top + sqrt2Width) - ..lineTo(rect.right - sqrt2Width, rect.bottom) - ..close(), - Path() // top - ..moveTo(rect.right, rect.top) - ..lineTo(rect.right, rect.bottom - sqrt2Width) - ..lineTo(rect.left + sqrt2Width, rect.top)); + PathOperation.union, + Path() // bottom + ..moveTo(rect.left, rect.bottom) + ..lineTo(rect.left, rect.top + sqrt2Width) + ..lineTo(rect.right - sqrt2Width, rect.bottom) + ..close(), + Path() // top + ..moveTo(rect.right, rect.top) + ..lineTo(rect.right, rect.bottom - sqrt2Width) + ..lineTo(rect.left + sqrt2Width, rect.top), + ); canvas ..save() diff --git a/lib/common/widgets/draggable_sheet/draggable_scrollable_sheet_dyn.dart b/lib/common/widgets/draggable_sheet/draggable_scrollable_sheet_dyn.dart index e8e541080..59585f9ef 100644 --- a/lib/common/widgets/draggable_sheet/draggable_scrollable_sheet_dyn.dart +++ b/lib/common/widgets/draggable_sheet/draggable_scrollable_sheet_dyn.dart @@ -104,16 +104,19 @@ class DraggableScrollableController extends ChangeNotifier { /// When calling [animateTo] in widget tests, `await`ing the returned /// [Future] may cause the test to hang and timeout. Instead, use /// [WidgetTester.pumpAndSettle]. - Future animateTo(double size, - {required Duration duration, required Curve curve}) async { + Future animateTo( + double size, { + required Duration duration, + required Curve curve, + }) async { _assertAttached(); assert(size >= 0 && size <= 1); assert(duration != Duration.zero); final AnimationController animationController = AnimationController.unbounded( - vsync: _attachedController!.position.context.vsync, - value: _attachedController!.extent.currentSize, - ); + vsync: _attachedController!.position.context.vsync, + value: _attachedController!.extent.currentSize, + ); _animationControllers.add(animationController); _attachedController!.position.goIdle(); // This disables any snapping until the next user interaction with the sheet. @@ -134,8 +137,11 @@ class DraggableScrollableController extends ChangeNotifier { ); }); await animationController.animateTo( - clampDouble(size, _attachedController!.extent.minSize, - _attachedController!.extent.maxSize), + clampDouble( + size, + _attachedController!.extent.minSize, + _attachedController!.extent.maxSize, + ), duration: duration, curve: curve, ); @@ -291,12 +297,13 @@ class DraggableScrollableSheet extends StatefulWidget { this.controller, this.shouldCloseOnMinExtent = true, required this.builder, - }) : assert(minChildSize >= 0.0), - assert(maxChildSize <= 1.0), - assert(minChildSize <= initialChildSize), - assert(initialChildSize <= maxChildSize), - assert(snapAnimationDuration == null || - snapAnimationDuration > Duration.zero); + }) : assert(minChildSize >= 0.0), + assert(maxChildSize <= 1.0), + assert(minChildSize <= initialChildSize), + assert(initialChildSize <= maxChildSize), + assert( + snapAnimationDuration == null || snapAnimationDuration > Duration.zero, + ); /// The initial fractional value of the parent container's height to use when /// displaying the widget. @@ -414,14 +421,14 @@ class _DraggableSheetExtent { bool? hasDragged, bool? hasChanged, this.shouldCloseOnMinExtent = true, - }) : assert(minSize >= 0), - assert(maxSize <= 1), - assert(minSize <= initialSize), - assert(initialSize <= maxSize), - _currentSize = currentSize ?? ValueNotifier(initialSize), - availablePixels = double.infinity, - hasDragged = hasDragged ?? false, - hasChanged = hasChanged ?? false { + }) : assert(minSize >= 0), + assert(maxSize <= 1), + assert(minSize <= initialSize), + assert(initialSize <= maxSize), + _currentSize = currentSize ?? ValueNotifier(initialSize), + availablePixels = double.infinity, + hasDragged = hasDragged ?? false, + hasChanged = hasChanged ?? false { assert(debugMaybeDispatchCreated('widgets', '_DraggableSheetExtent', this)); } @@ -569,8 +576,9 @@ class _DraggableScrollableSheetState extends State { initialSize: widget.initialChildSize, shouldCloseOnMinExtent: widget.shouldCloseOnMinExtent, ); - _scrollController = - _DraggableScrollableSheetScrollController(extent: _extent); + _scrollController = _DraggableScrollableSheetScrollController( + extent: _extent, + ); widget.controller?._attach(_scrollController); } @@ -621,17 +629,17 @@ class _DraggableScrollableSheetState extends State { valueListenable: _extent._currentSize, builder: (BuildContext context, double currentSize, Widget? child) => LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - _extent.availablePixels = - widget.maxChildSize * constraints.biggest.height; - final Widget sheet = FractionallySizedBox( - heightFactor: currentSize, - alignment: Alignment.bottomCenter, - child: child, - ); - return widget.expand ? SizedBox.expand(child: sheet) : sheet; - }, - ), + builder: (BuildContext context, BoxConstraints constraints) { + _extent.availablePixels = + widget.maxChildSize * constraints.biggest.height; + final Widget sheet = FractionallySizedBox( + heightFactor: currentSize, + alignment: Alignment.bottomCenter, + child: child, + ); + return widget.expand ? SizedBox.expand(child: sheet) : sheet; + }, + ), child: widget.builder(context, _scrollController), ); } @@ -675,9 +683,11 @@ class _DraggableScrollableSheetState extends State { // this runs-we can't use the previous extent's available pixels as it may // have changed when the widget was updated. WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { - for (int index = 0; - index < _scrollController.positions.length; - index++) { + for ( + int index = 0; + index < _scrollController.positions.length; + index++ + ) { final _DraggableScrollableSheetScrollPosition position = _scrollController.positions.elementAt(index) as _DraggableScrollableSheetScrollPosition; @@ -688,14 +698,17 @@ class _DraggableScrollableSheetState extends State { } String _snapSizeErrorMessage(int invalidIndex) { - final List snapSizesWithIndicator = - widget.snapSizes!.asMap().keys.map((int index) { - final String snapSizeString = widget.snapSizes![index].toString(); - if (index == invalidIndex) { - return '>>> $snapSizeString <<<'; - } - return snapSizeString; - }).toList(); + final List snapSizesWithIndicator = widget.snapSizes! + .asMap() + .keys + .map((int index) { + final String snapSizeString = widget.snapSizes![index].toString(); + if (index == invalidIndex) { + return '>>> $snapSizeString <<<'; + } + return snapSizeString; + }) + .toList(); return "Invalid snapSize '${widget.snapSizes![invalidIndex]}' at index $invalidIndex of:\n" ' $snapSizesWithIndicator'; } @@ -755,11 +768,16 @@ class _DraggableScrollableSheetScrollController extends ScrollController { // Just animate really fast. // Avoid doing it at all if the offset is already 0.0. if (offset != 0.0) { - animateTo(0.0, - duration: const Duration(milliseconds: 1), curve: Curves.linear); + animateTo( + 0.0, + duration: const Duration(milliseconds: 1), + curve: Curves.linear, + ); } extent.updateSize( - extent.initialSize, position.context.notificationContext!); + extent.initialSize, + position.context.notificationContext!, + ); } @override @@ -901,9 +919,12 @@ class _DraggableScrollableSheetScrollPosition final AnimationController ballisticController = AnimationController.unbounded( - debugLabel: objectRuntimeType(this, '_DraggableScrollableSheetPosition'), - vsync: context.vsync, - ); + debugLabel: objectRuntimeType( + this, + '_DraggableScrollableSheetPosition', + ), + vsync: context.vsync, + ); _ballisticControllers.add(ballisticController); double lastPosition = extent.currentPixels; @@ -916,7 +937,8 @@ class _DraggableScrollableSheetScrollPosition // Make sure we pass along enough velocity to keep scrolling - otherwise // we just "bounce" off the top making it look like the list doesn't // have more to scroll. - velocity = ballisticController.velocity + + velocity = + ballisticController.velocity + (physics.toleranceFor(this).velocity * ballisticController.velocity.sign); super.goBallistic(velocity); @@ -984,8 +1006,8 @@ class DraggableScrollableActuator extends StatefulWidget { /// some [DraggableScrollableSheet] is listening for updates, `false` /// otherwise. static bool reset(BuildContext context) { - final _InheritedResetNotifier? notifier = - context.dependOnInheritedWidgetOfExactType<_InheritedResetNotifier>(); + final _InheritedResetNotifier? notifier = context + .dependOnInheritedWidgetOfExactType<_InheritedResetNotifier>(); return notifier?._sendReset() ?? false; } @@ -1040,8 +1062,10 @@ class _ResetNotifier extends ChangeNotifier { class _InheritedResetNotifier extends InheritedNotifier<_ResetNotifier> { /// Creates an [InheritedNotifier] that the [DraggableScrollableSheet] will /// listen to for an indication that it should reset itself back to [DraggableScrollableSheet.initialChildSize]. - const _InheritedResetNotifier( - {required super.child, required _ResetNotifier super.notifier}); + const _InheritedResetNotifier({ + required super.child, + required _ResetNotifier super.notifier, + }); bool _sendReset() => notifier!.sendReset(); @@ -1050,8 +1074,8 @@ class _InheritedResetNotifier extends InheritedNotifier<_ResetNotifier> { /// /// Returns true if the notifier requested a reset, false otherwise. static bool shouldReset(BuildContext context) { - final InheritedWidget? widget = - context.dependOnInheritedWidgetOfExactType<_InheritedResetNotifier>(); + final InheritedWidget? widget = context + .dependOnInheritedWidgetOfExactType<_InheritedResetNotifier>(); if (widget == null) { return false; } @@ -1076,7 +1100,8 @@ class _SnappingSimulation extends Simulation { if (snapAnimationDuration != null && snapAnimationDuration.inMilliseconds > 0) { - velocity = (_pixelSnapSize - position) * + velocity = + (_pixelSnapSize - position) * 1000 / snapAnimationDuration.inMilliseconds; } @@ -1126,8 +1151,9 @@ class _SnappingSimulation extends Simulation { // non-zero, select the size in the velocity's direction. Otherwise, // the nearest snap size. double _getSnapSize(double initialVelocity, List pixelSnapSizes) { - final int indexOfNextSize = - pixelSnapSizes.indexWhere((double size) => size >= position); + final int indexOfNextSize = pixelSnapSizes.indexWhere( + (double size) => size >= position, + ); if (indexOfNextSize == 0) { return pixelSnapSizes.first; } diff --git a/lib/common/widgets/draggable_sheet/draggable_scrollable_sheet_topic.dart b/lib/common/widgets/draggable_sheet/draggable_scrollable_sheet_topic.dart index a2e6fb2be..b9c1c8707 100644 --- a/lib/common/widgets/draggable_sheet/draggable_scrollable_sheet_topic.dart +++ b/lib/common/widgets/draggable_sheet/draggable_scrollable_sheet_topic.dart @@ -104,16 +104,19 @@ class DraggableScrollableController extends ChangeNotifier { /// When calling [animateTo] in widget tests, `await`ing the returned /// [Future] may cause the test to hang and timeout. Instead, use /// [WidgetTester.pumpAndSettle]. - Future animateTo(double size, - {required Duration duration, required Curve curve}) async { + Future animateTo( + double size, { + required Duration duration, + required Curve curve, + }) async { _assertAttached(); assert(size >= 0 && size <= 1); assert(duration != Duration.zero); final AnimationController animationController = AnimationController.unbounded( - vsync: _attachedController!.position.context.vsync, - value: _attachedController!.extent.currentSize, - ); + vsync: _attachedController!.position.context.vsync, + value: _attachedController!.extent.currentSize, + ); _animationControllers.add(animationController); _attachedController!.position.goIdle(); // This disables any snapping until the next user interaction with the sheet. @@ -134,8 +137,11 @@ class DraggableScrollableController extends ChangeNotifier { ); }); await animationController.animateTo( - clampDouble(size, _attachedController!.extent.minSize, - _attachedController!.extent.maxSize), + clampDouble( + size, + _attachedController!.extent.minSize, + _attachedController!.extent.maxSize, + ), duration: duration, curve: curve, ); @@ -292,12 +298,13 @@ class DraggableScrollableSheet extends StatefulWidget { this.shouldCloseOnMinExtent = true, this.initialScrollOffset = 0, required this.builder, - }) : assert(minChildSize >= 0.0), - assert(maxChildSize <= 1.0), - assert(minChildSize <= initialChildSize), - assert(initialChildSize <= maxChildSize), - assert(snapAnimationDuration == null || - snapAnimationDuration > Duration.zero); + }) : assert(minChildSize >= 0.0), + assert(maxChildSize <= 1.0), + assert(minChildSize <= initialChildSize), + assert(initialChildSize <= maxChildSize), + assert( + snapAnimationDuration == null || snapAnimationDuration > Duration.zero, + ); final double initialScrollOffset; @@ -417,14 +424,14 @@ class _DraggableSheetExtent { bool? hasDragged, bool? hasChanged, this.shouldCloseOnMinExtent = true, - }) : assert(minSize >= 0), - assert(maxSize <= 1), - assert(minSize <= initialSize), - assert(initialSize <= maxSize), - _currentSize = currentSize ?? ValueNotifier(initialSize), - availablePixels = double.infinity, - hasDragged = hasDragged ?? false, - hasChanged = hasChanged ?? false { + }) : assert(minSize >= 0), + assert(maxSize <= 1), + assert(minSize <= initialSize), + assert(initialSize <= maxSize), + _currentSize = currentSize ?? ValueNotifier(initialSize), + availablePixels = double.infinity, + hasDragged = hasDragged ?? false, + hasChanged = hasChanged ?? false { assert(debugMaybeDispatchCreated('widgets', '_DraggableSheetExtent', this)); } @@ -626,17 +633,17 @@ class _DraggableScrollableSheetState extends State { valueListenable: _extent._currentSize, builder: (BuildContext context, double currentSize, Widget? child) => LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - _extent.availablePixels = - widget.maxChildSize * constraints.biggest.height; - final Widget sheet = FractionallySizedBox( - heightFactor: currentSize, - alignment: Alignment.bottomCenter, - child: child, - ); - return widget.expand ? SizedBox.expand(child: sheet) : sheet; - }, - ), + builder: (BuildContext context, BoxConstraints constraints) { + _extent.availablePixels = + widget.maxChildSize * constraints.biggest.height; + final Widget sheet = FractionallySizedBox( + heightFactor: currentSize, + alignment: Alignment.bottomCenter, + child: child, + ); + return widget.expand ? SizedBox.expand(child: sheet) : sheet; + }, + ), child: widget.builder(context, _scrollController), ); } @@ -680,9 +687,11 @@ class _DraggableScrollableSheetState extends State { // this runs-we can't use the previous extent's available pixels as it may // have changed when the widget was updated. WidgetsBinding.instance.addPostFrameCallback((Duration timeStamp) { - for (int index = 0; - index < _scrollController.positions.length; - index++) { + for ( + int index = 0; + index < _scrollController.positions.length; + index++ + ) { final _DraggableScrollableSheetScrollPosition position = _scrollController.positions.elementAt(index) as _DraggableScrollableSheetScrollPosition; @@ -693,14 +702,17 @@ class _DraggableScrollableSheetState extends State { } String _snapSizeErrorMessage(int invalidIndex) { - final List snapSizesWithIndicator = - widget.snapSizes!.asMap().keys.map((int index) { - final String snapSizeString = widget.snapSizes![index].toString(); - if (index == invalidIndex) { - return '>>> $snapSizeString <<<'; - } - return snapSizeString; - }).toList(); + final List snapSizesWithIndicator = widget.snapSizes! + .asMap() + .keys + .map((int index) { + final String snapSizeString = widget.snapSizes![index].toString(); + if (index == invalidIndex) { + return '>>> $snapSizeString <<<'; + } + return snapSizeString; + }) + .toList(); return "Invalid snapSize '${widget.snapSizes![invalidIndex]}' at index $invalidIndex of:\n" ' $snapSizesWithIndicator'; } @@ -766,11 +778,16 @@ class _DraggableScrollableSheetScrollController extends ScrollController { // Just animate really fast. // Avoid doing it at all if the offset is already 0.0. if (offset != 0.0) { - animateTo(0.0, - duration: const Duration(milliseconds: 1), curve: Curves.linear); + animateTo( + 0.0, + duration: const Duration(milliseconds: 1), + curve: Curves.linear, + ); } extent.updateSize( - extent.initialSize, position.context.notificationContext!); + extent.initialSize, + position.context.notificationContext!, + ); } @override @@ -905,9 +922,12 @@ class _DraggableScrollableSheetScrollPosition final AnimationController ballisticController = AnimationController.unbounded( - debugLabel: objectRuntimeType(this, '_DraggableScrollableSheetPosition'), - vsync: context.vsync, - ); + debugLabel: objectRuntimeType( + this, + '_DraggableScrollableSheetPosition', + ), + vsync: context.vsync, + ); _ballisticControllers.add(ballisticController); double lastPosition = extent.currentPixels; @@ -920,7 +940,8 @@ class _DraggableScrollableSheetScrollPosition // Make sure we pass along enough velocity to keep scrolling - otherwise // we just "bounce" off the top making it look like the list doesn't // have more to scroll. - velocity = ballisticController.velocity + + velocity = + ballisticController.velocity + (physics.toleranceFor(this).velocity * ballisticController.velocity.sign); super.goBallistic(velocity); @@ -987,8 +1008,8 @@ class DraggableScrollableActuator extends StatefulWidget { /// some [DraggableScrollableSheet] is listening for updates, `false` /// otherwise. static bool reset(BuildContext context) { - final _InheritedResetNotifier? notifier = - context.dependOnInheritedWidgetOfExactType<_InheritedResetNotifier>(); + final _InheritedResetNotifier? notifier = context + .dependOnInheritedWidgetOfExactType<_InheritedResetNotifier>(); return notifier?._sendReset() ?? false; } @@ -1043,8 +1064,10 @@ class _ResetNotifier extends ChangeNotifier { class _InheritedResetNotifier extends InheritedNotifier<_ResetNotifier> { /// Creates an [InheritedNotifier] that the [DraggableScrollableSheet] will /// listen to for an indication that it should reset itself back to [DraggableScrollableSheet.initialChildSize]. - const _InheritedResetNotifier( - {required super.child, required _ResetNotifier super.notifier}); + const _InheritedResetNotifier({ + required super.child, + required _ResetNotifier super.notifier, + }); bool _sendReset() => notifier!.sendReset(); @@ -1053,8 +1076,8 @@ class _InheritedResetNotifier extends InheritedNotifier<_ResetNotifier> { /// /// Returns true if the notifier requested a reset, false otherwise. static bool shouldReset(BuildContext context) { - final InheritedWidget? widget = - context.dependOnInheritedWidgetOfExactType<_InheritedResetNotifier>(); + final InheritedWidget? widget = context + .dependOnInheritedWidgetOfExactType<_InheritedResetNotifier>(); if (widget == null) { return false; } @@ -1079,7 +1102,8 @@ class _SnappingSimulation extends Simulation { if (snapAnimationDuration != null && snapAnimationDuration.inMilliseconds > 0) { - velocity = (_pixelSnapSize - position) * + velocity = + (_pixelSnapSize - position) * 1000 / snapAnimationDuration.inMilliseconds; } @@ -1129,8 +1153,9 @@ class _SnappingSimulation extends Simulation { // non-zero, select the size in the velocity's direction. Otherwise, // the nearest snap size. double _getSnapSize(double initialVelocity, List pixelSnapSizes) { - final int indexOfNextSize = - pixelSnapSizes.indexWhere((double size) => size >= position); + final int indexOfNextSize = pixelSnapSizes.indexWhere( + (double size) => size >= position, + ); if (indexOfNextSize == 0) { return pixelSnapSizes.first; } diff --git a/lib/common/widgets/image/image_view.dart b/lib/common/widgets/image/image_view.dart index 879baac18..15ff34363 100644 --- a/lib/common/widgets/image/image_view.dart +++ b/lib/common/widgets/image/image_view.dart @@ -54,8 +54,8 @@ Widget imageView( imageWidth = ratioWH > 1.5 ? maxWidth : (ratioWH >= 1 || (height > width && ratioHW < 1.5)) - ? 2 * imageWidth - : 1.5 * imageWidth; + ? 2 * imageWidth + : 1.5 * imageWidth; imageHeight = imageWidth * min(ratioHW, _maxRatio); } else if (picArr.length == 2) { imageWidth = imageHeight = 2 * imageWidth; @@ -66,19 +66,23 @@ Widget imageView( return StyleString.mdRadius; } return BorderRadius.only( - topLeft: index - row >= 0 || + topLeft: + index - row >= 0 || ((index - 1) >= 0 && (index - 1) % row < index % row) ? Radius.zero : StyleString.imgRadius, - topRight: index - row >= 0 || + topRight: + index - row >= 0 || ((index + 1) < picArr.length && (index + 1) % row > index % row) ? Radius.zero : StyleString.imgRadius, - bottomLeft: index + row < picArr.length || + bottomLeft: + index + row < picArr.length || ((index - 1) >= 0 && (index - 1) % row < index % row) ? Radius.zero : StyleString.imgRadius, - bottomRight: index + row < picArr.length || + bottomRight: + index + row < picArr.length || ((index + 1) < picArr.length && (index + 1) % row > index % row) ? Radius.zero : StyleString.imgRadius, @@ -105,8 +109,9 @@ Widget imageView( (item) { bool isLive = item.isLivePhoto; return SourceModel( - sourceType: - isLive ? SourceType.livePhoto : SourceType.networkImage, + sourceType: isLive + ? SourceType.livePhoto + : SourceType.networkImage, url: item.url, liveUrl: isLive ? item.liveUrl : null, width: isLive ? parseSize(item.width) : null, @@ -152,10 +157,9 @@ Widget imageView( width: imageWidth, height: imageHeight, decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .onInverseSurface - .withValues(alpha: 0.4), + color: Theme.of( + context, + ).colorScheme.onInverseSurface.withValues(alpha: 0.4), borderRadius: borderRadius(index), ), child: Center( diff --git a/lib/common/widgets/image/network_img_layer.dart b/lib/common/widgets/image/network_img_layer.dart index 565e8f137..0adb8d520 100644 --- a/lib/common/widgets/image/network_img_layer.dart +++ b/lib/common/widgets/image/network_img_layer.dart @@ -44,15 +44,15 @@ class NetworkImgLayer extends StatelessWidget { Widget build(BuildContext context) { return src?.isNotEmpty == true ? type == ImageType.avatar - ? ClipOval(child: _buildImage(context)) - : radius == 0 || type == ImageType.emote - ? _buildImage(context) - : ClipRRect( - borderRadius: radius != null - ? BorderRadius.circular(radius!) - : StyleString.mdRadius, - child: _buildImage(context), - ) + ? ClipOval(child: _buildImage(context)) + : radius == 0 || type == ImageType.emote + ? _buildImage(context) + : ClipRRect( + borderRadius: radius != null + ? BorderRadius.circular(radius!) + : StyleString.mdRadius, + child: _buildImage(context), + ) : getPlaceHolder?.call() ?? placeholder(context); } @@ -70,8 +70,9 @@ class NetworkImgLayer extends StatelessWidget { memCacheWidth: memCacheWidth, memCacheHeight: memCacheHeight, fit: boxFit ?? BoxFit.cover, - alignment: - isLongPic?.call() == true ? Alignment.topCenter : Alignment.center, + alignment: isLongPic?.call() == true + ? Alignment.topCenter + : Alignment.center, fadeOutDuration: fadeOutDuration ?? const Duration(milliseconds: 120), fadeInDuration: fadeInDuration ?? const Duration(milliseconds: 120), filterQuality: FilterQuality.low, @@ -89,16 +90,15 @@ class NetworkImgLayer extends StatelessWidget { clipBehavior: Clip.antiAlias, decoration: BoxDecoration( shape: type == ImageType.avatar ? BoxShape.circle : BoxShape.rectangle, - color: Theme.of(context) - .colorScheme - .onInverseSurface - .withValues(alpha: 0.4), + color: Theme.of( + context, + ).colorScheme.onInverseSurface.withValues(alpha: 0.4), borderRadius: type == ImageType.avatar || type == ImageType.emote || radius == 0 - ? null - : radius != null - ? BorderRadius.circular(radius!) - : StyleString.mdRadius, + ? null + : radius != null + ? BorderRadius.circular(radius!) + : StyleString.mdRadius, ), child: Center( child: Image.asset( diff --git a/lib/common/widgets/image/nine_grid_view.dart b/lib/common/widgets/image/nine_grid_view.dart index 08d2ce17a..0174bcf5a 100644 --- a/lib/common/widgets/image/nine_grid_view.dart +++ b/lib/common/widgets/image/nine_grid_view.dart @@ -133,7 +133,8 @@ class _NineGridViewState extends State { if (widget.itemCount == 0) { return Rect.fromLTRB(0, 0, padding.horizontal, padding.vertical); } - double width = widget.width ?? + double width = + widget.width ?? (MediaQuery.sizeOf(context).width - widget.margin.horizontal); width = width - padding.horizontal; double space = widget.space; @@ -158,18 +159,22 @@ class _NineGridViewState extends State { /// build nine grid view. Widget _buildChild(BuildContext context, double itemW) { double space = widget.space; - int column = - (widget.itemCount == 4 && widget.type != NineGridType.normal) ? 2 : 3; + int column = (widget.itemCount == 4 && widget.type != NineGridType.normal) + ? 2 + : 3; List list = []; for (int i = 0; i < widget.itemCount; i++) { - list.add(Positioned( + list.add( + Positioned( top: (space + itemW) * (i ~/ column), left: (space + itemW) * (i % column), child: SizedBox( width: itemW, height: itemW, child: widget.itemBuilder(context, i), - ))); + ), + ), + ); } return Stack( clipBehavior: Clip.none, @@ -191,11 +196,14 @@ class _NineGridViewState extends State { if (!_isZero(bigImgWidth) && !_isZero(bigImgHeight)) { return _getOneChild(context, bigImgWidth!, bigImgHeight!); } else { - _ImageUtil().getImageSize(widget.bigImage)?.then((rect) { - ngvBigImageSizeMap[bigImageUrl] = rect; - if (!mounted) return; - setState(() {}); - }).catchError((e) {}); + _ImageUtil() + .getImageSize(widget.bigImage) + ?.then((rect) { + ngvBigImageSizeMap[bigImageUrl] = rect; + if (!mounted) return; + setState(() {}); + }) + .catchError((e) {}); } } return null; @@ -238,7 +246,8 @@ class _NineGridViewState extends State { for (int i = 0; i < widget.itemCount; i++) { double left; if (first > 0 && i < first) { - left = (width - itemW * first - space * (first - 1)) / 2 + + left = + (width - itemW * first - space * (first - 1)) / 2 + (itemW + space) * i; } else { left = (space + itemW) * ((i - first) % column); @@ -248,17 +257,21 @@ class _NineGridViewState extends State { ? 0 : (first > 0 ? (i + column - first) : i) ~/ column; - double top = (width - itemW * row - space * (row - 1)) / 2 + + double top = + (width - itemW * row - space * (row - 1)) / 2 + (space + itemW) * itemIndex; - list.add(Positioned( + list.add( + Positioned( top: top, left: left, child: SizedBox( width: itemW, height: itemW, child: widget.itemBuilder(context, i), - ))); + ), + ), + ); } return Stack( clipBehavior: Clip.none, @@ -273,18 +286,22 @@ class _NineGridViewState extends State { double itemW = (width - widget.space) / 2; List children = []; for (int i = 0; i < itemCount; i++) { - children.add(Positioned( + children.add( + Positioned( top: (widget.space + itemW) * (i ~/ 2), - left: (widget.space + itemW) * + left: + (widget.space + itemW) * (((itemCount == 3 && i == 2) ? i + 1 : i) % 2), child: SizedBox( width: itemCount == 1 ? width : itemW, height: (itemCount == 1 || itemCount == 2 || (itemCount == 3 && i == 0)) - ? width - : itemW, + ? width + : itemW, child: widget.itemBuilder(context, i), - ))); + ), + ), + ); } return ClipOval( child: Stack( @@ -300,11 +317,12 @@ class _NineGridViewState extends State { int itemCount = math.min(5, widget.itemCount); if (itemCount == 1) { return ClipOval( - child: SizedBox( - width: width, - height: width, - child: widget.itemBuilder(context, 0), - )); + child: SizedBox( + width: width, + height: width, + child: widget.itemBuilder(context, 0), + ), + ); } List children = []; @@ -323,7 +341,8 @@ class _NineGridViewState extends State { startDegree = 210; r = width / (2 + 4 * math.sin(math.pi * (3 - 2) / (2 * 3))); r1 = r / math.cos(math.pi * (3 - 2) / (2 * 3)); - double R = r * + double R = + r * (1 + math.sin(math.pi / itemCount)) / math.sin(math.pi / itemCount); double dy = 0.5 * (width - R - r * (1 + 1 / math.tan(math.pi / 3))); @@ -338,7 +357,8 @@ class _NineGridViewState extends State { startDegree = 126; r = width / (2 + 4 * math.sin(math.pi * (5 - 2) / (2 * 5))); r1 = r / math.cos(math.pi * (5 - 2) / (2 * 5)); - double R = r * + double R = + r * (1 + math.sin(math.pi / itemCount)) / math.sin(math.pi / itemCount); double dy = 0.5 * (width - R - r * (1 + 1 / math.tan(math.pi / 5))); @@ -388,7 +408,8 @@ class _NineGridViewState extends State { /// get big image size. Rect _getBigImgSize(double originalWidth, double originalHeight) { - double width = widget.width ?? + double width = + widget.width ?? (MediaQuery.sizeOf(context).width - widget.margin.horizontal); width = width - widget.padding.horizontal; double itemW = (width - widget.space * 2) / 3; @@ -475,8 +496,14 @@ class _ImageUtil { (ImageInfo info, bool synchronousCall) { imageStream.removeListener(listener); if (!completer.isCompleted) { - completer.complete(Rect.fromLTWH( - 0, 0, info.image.width.toDouble(), info.image.height.toDouble())); + completer.complete( + Rect.fromLTWH( + 0, + 0, + info.image.width.toDouble(), + info.image.height.toDouble(), + ), + ); } }, onError: (dynamic exception, StackTrace? stackTrace) { @@ -535,8 +562,10 @@ class QQClipper extends CustomClipper { points.add(Offset(x1, y1)); } - double spaceB = math.atan( - r * math.sin(d2r(spaceA)) / (2 * r - r * math.cos(d2r(spaceA)))) / + double spaceB = + math.atan( + r * math.sin(d2r(spaceA)) / (2 * r - r * math.cos(d2r(spaceA))), + ) / math.pi * 180; double r1 = (2 * r - r * math.cos(d2r(spaceA))) / math.cos(d2r(spaceB)); diff --git a/lib/common/widgets/interactiveviewer_gallery/interactive_viewer.dart b/lib/common/widgets/interactiveviewer_gallery/interactive_viewer.dart index bfaa7519e..a5fab49bd 100644 --- a/lib/common/widgets/interactiveviewer_gallery/interactive_viewer.dart +++ b/lib/common/widgets/interactiveviewer_gallery/interactive_viewer.dart @@ -22,8 +22,8 @@ import 'package:vector_math/vector_math_64.dart' show Matrix4, Quad, Vector3; /// /// * [InteractiveViewer.builder], whose builder is of this type. /// * [WidgetBuilder], which is similar, but takes no viewport. -typedef InteractiveViewerWidgetBuilder = Widget Function( - BuildContext context, Quad viewport); +typedef InteractiveViewerWidgetBuilder = + Widget Function(BuildContext context, Quad viewport); /// A widget that enables pan and zoom interactions with its child. /// @@ -82,23 +82,23 @@ class InteractiveViewer extends StatefulWidget { this.onReset, this.isAnimating, required Widget this.child, - }) : assert(minScale > 0), - assert(interactionEndFrictionCoefficient > 0), - assert(minScale.isFinite), - assert(maxScale > 0), - assert(!maxScale.isNaN), - assert(maxScale >= minScale), - // boundaryMargin must be either fully infinite or fully finite, but not - // a mix of both. - assert( - (boundaryMargin.horizontal.isInfinite && - boundaryMargin.vertical.isInfinite) || - (boundaryMargin.top.isFinite && - boundaryMargin.right.isFinite && - boundaryMargin.bottom.isFinite && - boundaryMargin.left.isFinite), - ), - builder = null; + }) : assert(minScale > 0), + assert(interactionEndFrictionCoefficient > 0), + assert(minScale.isFinite), + assert(maxScale > 0), + assert(!maxScale.isNaN), + assert(maxScale >= minScale), + // boundaryMargin must be either fully infinite or fully finite, but not + // a mix of both. + assert( + (boundaryMargin.horizontal.isInfinite && + boundaryMargin.vertical.isInfinite) || + (boundaryMargin.top.isFinite && + boundaryMargin.right.isFinite && + boundaryMargin.bottom.isFinite && + boundaryMargin.left.isFinite), + ), + builder = null; /// Creates an InteractiveViewer for a child that is created on demand. /// @@ -132,24 +132,24 @@ class InteractiveViewer extends StatefulWidget { this.onReset, this.isAnimating, required InteractiveViewerWidgetBuilder this.builder, - }) : assert(minScale > 0), - assert(interactionEndFrictionCoefficient > 0), - assert(minScale.isFinite), - assert(maxScale > 0), - assert(!maxScale.isNaN), - assert(maxScale >= minScale), - // boundaryMargin must be either fully infinite or fully finite, but not - // a mix of both. - assert( - (boundaryMargin.horizontal.isInfinite && - boundaryMargin.vertical.isInfinite) || - (boundaryMargin.top.isFinite && - boundaryMargin.right.isFinite && - boundaryMargin.bottom.isFinite && - boundaryMargin.left.isFinite), - ), - constrained = false, - child = null; + }) : assert(minScale > 0), + assert(interactionEndFrictionCoefficient > 0), + assert(minScale.isFinite), + assert(maxScale > 0), + assert(!maxScale.isNaN), + assert(maxScale >= minScale), + // boundaryMargin must be either fully infinite or fully finite, but not + // a mix of both. + assert( + (boundaryMargin.horizontal.isInfinite && + boundaryMargin.vertical.isInfinite) || + (boundaryMargin.top.isFinite && + boundaryMargin.right.isFinite && + boundaryMargin.bottom.isFinite && + boundaryMargin.left.isFinite), + ), + constrained = false, + child = null; final Function? isAnimating; final VoidCallback? onReset; @@ -402,7 +402,8 @@ class InteractiveViewer extends StatefulWidget { /// Returns the closest point to the given point on the given line segment. @visibleForTesting static Vector3 getNearestPointOnLine(Vector3 point, Vector3 l1, Vector3 l2) { - final double lengthSquared = math.pow(l2.x - l1.x, 2.0).toDouble() + + final double lengthSquared = + math.pow(l2.x - l1.x, 2.0).toDouble() + math.pow(l2.y - l1.y, 2.0).toDouble(); // In this case, l1 == l2. @@ -414,8 +415,11 @@ class InteractiveViewer extends StatefulWidget { // the point. final Vector3 l1P = point - l1; final Vector3 l1L2 = l2 - l1; - final double fraction = - clampDouble(l1P.dot(l1L2) / lengthSquared, 0.0, 1.0); + final double fraction = clampDouble( + l1P.dot(l1L2) / lengthSquared, + 0.0, + 1.0, + ); return l1 + l1L2 * fraction; } @@ -558,8 +562,9 @@ class _InteractiveViewerState extends State final RenderBox childRenderBox = _childKey.currentContext!.findRenderObject()! as RenderBox; final Size childSize = childRenderBox.size; - final Rect boundaryRect = - widget.boundaryMargin.inflateRect(Offset.zero & childSize); + final Rect boundaryRect = widget.boundaryMargin.inflateRect( + Offset.zero & childSize, + ); assert( !boundaryRect.isEmpty, "InteractiveViewer's child must have nonzero dimensions.", @@ -631,8 +636,10 @@ class _InteractiveViewerState extends State ); // If the given translation fits completely within the boundaries, allow it. - final Offset offendingDistance = - _exceedsBy(boundariesAabbQuad, nextViewport); + final Offset offendingDistance = _exceedsBy( + boundariesAabbQuad, + nextViewport, + ); if (offendingDistance == Offset.zero) { return nextMatrix; } @@ -651,17 +658,23 @@ class _InteractiveViewerState extends State // complicated than this when rotated. // https://github.com/flutter/flutter/issues/57698 final Matrix4 correctedMatrix = matrix.clone() - ..setTranslation(Vector3( - correctedTotalTranslation.dx, - correctedTotalTranslation.dy, - 0.0, - )); + ..setTranslation( + Vector3( + correctedTotalTranslation.dx, + correctedTotalTranslation.dy, + 0.0, + ), + ); // Double check that the corrected translation fits. - final Quad correctedViewport = - _transformViewport(correctedMatrix, _viewport); - final Offset offendingCorrectedDistance = - _exceedsBy(boundariesAabbQuad, correctedViewport); + final Quad correctedViewport = _transformViewport( + correctedMatrix, + _viewport, + ); + final Offset offendingCorrectedDistance = _exceedsBy( + boundariesAabbQuad, + correctedViewport, + ); if (offendingCorrectedDistance == Offset.zero) { return correctedMatrix; } @@ -680,12 +693,13 @@ class _InteractiveViewerState extends State offendingCorrectedDistance.dx == 0.0 ? correctedTotalTranslation.dx : 0.0, offendingCorrectedDistance.dy == 0.0 ? correctedTotalTranslation.dy : 0.0, ); - return matrix.clone() - ..setTranslation(Vector3( + return matrix.clone()..setTranslation( + Vector3( unidirectionalCorrectedTotalTranslation.dx, unidirectionalCorrectedTotalTranslation.dy, 0.0, - )); + ), + ); } // Return a new matrix representing the given matrix after applying the given @@ -698,8 +712,8 @@ class _InteractiveViewerState extends State // Don't allow a scale that results in an overall scale beyond min/max // scale. - final double currentScale = - _transformationController!.value.getMaxScaleOnAxis(); + final double currentScale = _transformationController!.value + .getMaxScaleOnAxis(); final double totalScale = math.max( currentScale * scale, // Ensure that the scale cannot make the child so big that it can't fit @@ -933,10 +947,12 @@ class _InteractiveViewerState extends State _currentAxis = null; return; } - final Vector3 translationVector = - _transformationController!.value.getTranslation(); - final Offset translation = - Offset(translationVector.x, translationVector.y); + final Vector3 translationVector = _transformationController!.value + .getTranslation(); + final Offset translation = Offset( + translationVector.x, + translationVector.y, + ); final FrictionSimulation frictionSimulationX = FrictionSimulation( widget.interactionEndFrictionCoefficient, translation.dx, @@ -951,13 +967,19 @@ class _InteractiveViewerState extends State details.velocity.pixelsPerSecond.distance, widget.interactionEndFrictionCoefficient, ); - _animation = Tween( - begin: translation, - end: Offset(frictionSimulationX.finalX, frictionSimulationY.finalX), - ).animate(CurvedAnimation( - parent: _controller, - curve: Curves.decelerate, - )); + _animation = + Tween( + begin: translation, + end: Offset( + frictionSimulationX.finalX, + frictionSimulationY.finalX, + ), + ).animate( + CurvedAnimation( + parent: _controller, + curve: Curves.decelerate, + ), + ); _controller.duration = Duration(milliseconds: (tFinal * 1000).round()); _animation!.addListener(_onAnimate); _controller.forward(); @@ -966,21 +988,31 @@ class _InteractiveViewerState extends State _currentAxis = null; return; } - final double scale = - _transformationController!.value.getMaxScaleOnAxis(); + final double scale = _transformationController!.value + .getMaxScaleOnAxis(); final FrictionSimulation frictionSimulation = FrictionSimulation( - widget.interactionEndFrictionCoefficient * widget.scaleFactor, - scale, - details.scaleVelocity / 10); - final double tFinal = _getFinalTime(details.scaleVelocity.abs(), - widget.interactionEndFrictionCoefficient, - effectivelyMotionless: 0.1); + widget.interactionEndFrictionCoefficient * widget.scaleFactor, + scale, + details.scaleVelocity / 10, + ); + final double tFinal = _getFinalTime( + details.scaleVelocity.abs(), + widget.interactionEndFrictionCoefficient, + effectivelyMotionless: 0.1, + ); _scaleAnimation = - Tween(begin: scale, end: frictionSimulation.x(tFinal)) - .animate(CurvedAnimation( - parent: _scaleController, curve: Curves.decelerate)); - _scaleController.duration = - Duration(milliseconds: (tFinal * 1000).round()); + Tween( + begin: scale, + end: frictionSimulation.x(tFinal), + ).animate( + CurvedAnimation( + parent: _scaleController, + curve: Curves.decelerate, + ), + ); + _scaleController.duration = Duration( + milliseconds: (tFinal * 1000).round(), + ); _scaleAnimation!.addListener(_onScaleAnimate); _scaleController.forward(); case _GestureType.rotate || null: @@ -1009,11 +1041,13 @@ class _InteractiveViewerState extends State ); if (!_gestureIsSupported(_GestureType.pan)) { - widget.onInteractionUpdate?.call(ScaleUpdateDetails( - focalPoint: event.position - event.scrollDelta, - localFocalPoint: event.localPosition - event.scrollDelta, - focalPointDelta: -localDelta, - )); + widget.onInteractionUpdate?.call( + ScaleUpdateDetails( + focalPoint: event.position - event.scrollDelta, + localFocalPoint: event.localPosition - event.scrollDelta, + focalPointDelta: -localDelta, + ), + ); widget.onInteractionEnd?.call(ScaleEndDetails()); return; } @@ -1027,13 +1061,17 @@ class _InteractiveViewerState extends State ); _transformationController!.value = _matrixTranslate( - _transformationController!.value, - newFocalPointScene - focalPointScene); + _transformationController!.value, + newFocalPointScene - focalPointScene, + ); - widget.onInteractionUpdate?.call(ScaleUpdateDetails( + widget.onInteractionUpdate?.call( + ScaleUpdateDetails( focalPoint: event.position - event.scrollDelta, localFocalPoint: event.localPosition - localDelta, - focalPointDelta: -localDelta)); + focalPointDelta: -localDelta, + ), + ); widget.onInteractionEnd?.call(ScaleEndDetails()); return; } @@ -1055,11 +1093,13 @@ class _InteractiveViewerState extends State ); if (!_gestureIsSupported(_GestureType.scale)) { - widget.onInteractionUpdate?.call(ScaleUpdateDetails( - focalPoint: event.position, - localFocalPoint: event.localPosition, - scale: scaleChange, - )); + widget.onInteractionUpdate?.call( + ScaleUpdateDetails( + focalPoint: event.position, + localFocalPoint: event.localPosition, + scale: scaleChange, + ), + ); widget.onInteractionEnd?.call(ScaleEndDetails()); return; } @@ -1083,11 +1123,13 @@ class _InteractiveViewerState extends State focalPointSceneScaled - focalPointScene, ); - widget.onInteractionUpdate?.call(ScaleUpdateDetails( - focalPoint: event.position, - localFocalPoint: event.localPosition, - scale: scaleChange, - )); + widget.onInteractionUpdate?.call( + ScaleUpdateDetails( + focalPoint: event.position, + localFocalPoint: event.localPosition, + scale: scaleChange, + ), + ); widget.onInteractionEnd?.call(ScaleEndDetails()); } @@ -1101,8 +1143,8 @@ class _InteractiveViewerState extends State return; } // Translate such that the resulting translation is _animation.value. - final Vector3 translationVector = - _transformationController!.value.getTranslation(); + final Vector3 translationVector = _transformationController!.value + .getTranslation(); final Offset translation = Offset(translationVector.x, translationVector.y); final Offset translationScene = _transformationController!.toScene( translation, @@ -1176,27 +1218,33 @@ class _InteractiveViewerState extends State // transformationControllers. if (oldWidget.transformationController == null) { if (widget.transformationController != null) { - _transformationController! - .removeListener(_onTransformationControllerChange); + _transformationController!.removeListener( + _onTransformationControllerChange, + ); _transformationController!.dispose(); _transformationController = widget.transformationController; - _transformationController! - .addListener(_onTransformationControllerChange); + _transformationController!.addListener( + _onTransformationControllerChange, + ); } } else { if (widget.transformationController == null) { - _transformationController! - .removeListener(_onTransformationControllerChange); + _transformationController!.removeListener( + _onTransformationControllerChange, + ); _transformationController = TransformationController(); - _transformationController! - .addListener(_onTransformationControllerChange); + _transformationController!.addListener( + _onTransformationControllerChange, + ); } else if (widget.transformationController != oldWidget.transformationController) { - _transformationController! - .removeListener(_onTransformationControllerChange); + _transformationController!.removeListener( + _onTransformationControllerChange, + ); _transformationController = widget.transformationController; - _transformationController! - .addListener(_onTransformationControllerChange); + _transformationController!.addListener( + _onTransformationControllerChange, + ); } } } @@ -1205,8 +1253,9 @@ class _InteractiveViewerState extends State void dispose() { _controller.dispose(); _scaleController.dispose(); - _transformationController! - .removeListener(_onTransformationControllerChange); + _transformationController!.removeListener( + _onTransformationControllerChange, + ); if (widget.transformationController == null) { _transformationController!.dispose(); } @@ -1329,7 +1378,7 @@ class TransformationController extends ValueNotifier { /// The [value] defaults to the identity matrix, which corresponds to no /// transformation. TransformationController([Matrix4? value]) - : super(value ?? Matrix4.identity()); + : super(value ?? Matrix4.identity()); /// Return the scene point at the given viewport point. /// @@ -1365,11 +1414,13 @@ class TransformationController extends ValueNotifier { // On viewportPoint, perform the inverse transformation of the scene to get // where the point would be in the scene before the transformation. final Matrix4 inverseMatrix = Matrix4.inverted(value); - final Vector3 untransformed = inverseMatrix.transform3(Vector3( - viewportPoint.dx, - viewportPoint.dy, - 0, - )); + final Vector3 untransformed = inverseMatrix.transform3( + Vector3( + viewportPoint.dx, + viewportPoint.dy, + 0, + ), + ); return Offset(untransformed.x, untransformed.y); } } @@ -1384,8 +1435,11 @@ enum _GestureType { // Given a velocity and drag, calculate the time at which motion will come to // a stop, within the margin of effectivelyMotionless. -double _getFinalTime(double velocity, double drag, - {double effectivelyMotionless = 10}) { +double _getFinalTime( + double velocity, + double drag, { + double effectivelyMotionless = 10, +}) { return math.log(effectivelyMotionless / velocity) / math.log(drag / 100); } @@ -1402,26 +1456,34 @@ Offset _getMatrixTranslation(Matrix4 matrix) { Quad _transformViewport(Matrix4 matrix, Rect viewport) { final Matrix4 inverseMatrix = matrix.clone()..invert(); return Quad.points( - inverseMatrix.transform3(Vector3( - viewport.topLeft.dx, - viewport.topLeft.dy, - 0.0, - )), - inverseMatrix.transform3(Vector3( - viewport.topRight.dx, - viewport.topRight.dy, - 0.0, - )), - inverseMatrix.transform3(Vector3( - viewport.bottomRight.dx, - viewport.bottomRight.dy, - 0.0, - )), - inverseMatrix.transform3(Vector3( - viewport.bottomLeft.dx, - viewport.bottomLeft.dy, - 0.0, - )), + inverseMatrix.transform3( + Vector3( + viewport.topLeft.dx, + viewport.topLeft.dy, + 0.0, + ), + ), + inverseMatrix.transform3( + Vector3( + viewport.topRight.dx, + viewport.topRight.dy, + 0.0, + ), + ), + inverseMatrix.transform3( + Vector3( + viewport.bottomRight.dx, + viewport.bottomRight.dy, + 0.0, + ), + ), + inverseMatrix.transform3( + Vector3( + viewport.bottomLeft.dx, + viewport.bottomLeft.dy, + 0.0, + ), + ), ); } @@ -1453,8 +1515,10 @@ Offset _exceedsBy(Quad boundary, Quad viewport) { ]; Offset largestExcess = Offset.zero; for (final Vector3 point in viewportPoints) { - final Vector3 pointInside = - InteractiveViewer.getNearestPointInside(point, boundary); + final Vector3 pointInside = InteractiveViewer.getNearestPointInside( + point, + boundary, + ); final Offset excess = Offset( pointInside.x - point.x, pointInside.y - point.y, diff --git a/lib/common/widgets/interactiveviewer_gallery/interactive_viewer_boundary.dart b/lib/common/widgets/interactiveviewer_gallery/interactive_viewer_boundary.dart index 17dbe874e..cf6673ab4 100644 --- a/lib/common/widgets/interactiveviewer_gallery/interactive_viewer_boundary.dart +++ b/lib/common/widgets/interactiveviewer_gallery/interactive_viewer_boundary.dart @@ -213,15 +213,15 @@ class InteractiveViewerBoundaryState extends State } Widget get content => DecoratedBoxTransition( - decoration: _opacityAnimation, - child: SlideTransition( - position: _slideAnimation, - child: ScaleTransition( - scale: _scaleAnimation, - child: widget.child, - ), - ), - ); + decoration: _opacityAnimation, + child: SlideTransition( + position: _slideAnimation, + child: ScaleTransition( + scale: _scaleAnimation, + child: widget.child, + ), + ), + ); @override Widget build(BuildContext context) { diff --git a/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart b/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart index 7ba92e2bf..edd4fef22 100644 --- a/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart +++ b/lib/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart @@ -28,8 +28,13 @@ import 'package:media_kit_video/media_kit_video.dart'; /// source is hit after zooming in to disable or enable the swiping gesture of /// the [PageView]. /// -typedef IndexedFocusedWidgetBuilder = Widget Function( - BuildContext context, int index, bool isFocus, bool enablePageView); +typedef IndexedFocusedWidgetBuilder = + Widget Function( + BuildContext context, + int index, + bool isFocus, + bool enablePageView, + ); typedef IndexedTagStringBuilder = String Function(int index); @@ -233,12 +238,13 @@ class _InteractiveviewerGalleryState extends State if (_transformationController!.value != Matrix4.identity()) { // animate the reset for the transformation of the interactive viewer - _animation = Matrix4Tween( - begin: _transformationController!.value, - end: Matrix4.identity(), - ).animate( - CurveTween(curve: Curves.easeOut).animate(_animationController), - ); + _animation = + Matrix4Tween( + begin: _transformationController!.value, + end: Matrix4.identity(), + ).animate( + CurveTween(curve: Curves.easeOut).animate(_animationController), + ); _animationController.forward(from: 0); } @@ -287,20 +293,27 @@ class _InteractiveviewerGalleryState extends State child: PageView.builder( onPageChanged: _onPageChanged, controller: _pageController, - physics: - _enablePageView ? null : const NeverScrollableScrollPhysics(), + physics: _enablePageView + ? null + : const NeverScrollableScrollPhysics(), itemCount: widget.sources.length, itemBuilder: (BuildContext context, int index) { final item = widget.sources[index]; return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () => EasyThrottle.throttle( - 'preview', const Duration(milliseconds: 555), onClose), + 'preview', + const Duration(milliseconds: 555), + onClose, + ), onDoubleTapDown: (TapDownDetails details) { _doubleTapLocalPosition = details.localPosition; }, onDoubleTap: () => EasyThrottle.throttle( - 'preview', const Duration(milliseconds: 555), onDoubleTap), + 'preview', + const Duration(milliseconds: 555), + onDoubleTap, + ), onLongPress: item.sourceType == SourceType.fileImage ? null : () => onLongPress(item), @@ -321,7 +334,8 @@ class _InteractiveviewerGalleryState extends State left: 0, right: 0, child: Container( - padding: MediaQuery.paddingOf(context) + + padding: + MediaQuery.paddingOf(context) + const EdgeInsets.fromLTRB(12, 8, 20, 8), decoration: _enablePageView ? BoxDecoration( @@ -330,7 +344,7 @@ class _InteractiveviewerGalleryState extends State end: Alignment.bottomCenter, colors: [ Colors.transparent, - Colors.black.withValues(alpha: 0.3) + Colors.black.withValues(alpha: 0.3), ], ), ) @@ -419,30 +433,32 @@ class _InteractiveviewerGalleryState extends State tag: item.url, child: switch (item.sourceType) { SourceType.fileImage => Image( - filterQuality: FilterQuality.low, - image: FileImage(File(item.url)), - ), + filterQuality: FilterQuality.low, + image: FileImage(File(item.url)), + ), SourceType.networkImage => CachedNetworkImage( - fadeInDuration: Duration.zero, - fadeOutDuration: Duration.zero, - imageUrl: _getActualUrl(item.url), - placeholderFadeInDuration: Duration.zero, - placeholder: (context, url) { - return CachedNetworkImage( - fadeInDuration: Duration.zero, - fadeOutDuration: Duration.zero, - imageUrl: ImageUtil.thumbnailUrl(item.url, widget.quality), - ); - }, - ), - SourceType.livePhoto => Obx(() => currentIndex.value == index - ? IgnorePointer( - child: Video( - controller: _videoController!, - fill: Colors.transparent, - ), - ) - : const SizedBox.shrink()), + fadeInDuration: Duration.zero, + fadeOutDuration: Duration.zero, + imageUrl: _getActualUrl(item.url), + placeholderFadeInDuration: Duration.zero, + placeholder: (context, url) { + return CachedNetworkImage( + fadeInDuration: Duration.zero, + fadeOutDuration: Duration.zero, + imageUrl: ImageUtil.thumbnailUrl(item.url, widget.quality), + ); + }, + ), + SourceType.livePhoto => Obx( + () => currentIndex.value == index + ? IgnorePointer( + child: Video( + controller: _videoController!, + fill: Colors.transparent, + ), + ) + : const SizedBox.shrink(), + ), }, ), ); @@ -481,15 +497,16 @@ class _InteractiveviewerGalleryState extends State offSetX, offSetY, matrix.row2.w, - matrix.row3.w + matrix.row3.w, ]); - _animation = Matrix4Tween( - begin: _transformationController!.value, - end: matrix, - ).animate( - CurveTween(curve: Curves.easeOut).animate(_animationController), - ); + _animation = + Matrix4Tween( + begin: _transformationController!.value, + end: matrix, + ).animate( + CurveTween(curve: Curves.easeOut).animate(_animationController), + ); _animationController .forward(from: 0) .whenComplete(() => _onScaleChanged(targetScale)); diff --git a/lib/common/widgets/loading_widget/loading_widget.dart b/lib/common/widgets/loading_widget/loading_widget.dart index 2b7f0c61a..3dc3ee6cc 100644 --- a/lib/common/widgets/loading_widget/loading_widget.dart +++ b/lib/common/widgets/loading_widget/loading_widget.dart @@ -7,17 +7,17 @@ Widget get linearLoading => const SliverToBoxAdapter(child: LinearProgressIndicator()); Widget errorWidget({errMsg, onReload}) => HttpError( - isSliver: false, - errMsg: errMsg, - onReload: onReload, - ); + isSliver: false, + errMsg: errMsg, + onReload: onReload, +); Widget scrollErrorWidget({errMsg, onReload, controller}) => CustomScrollView( - controller: controller, - slivers: [ - HttpError( - errMsg: errMsg, - onReload: onReload, - ) - ], - ); + controller: controller, + slivers: [ + HttpError( + errMsg: errMsg, + onReload: onReload, + ), + ], +); diff --git a/lib/common/widgets/page/page_view.dart b/lib/common/widgets/page/page_view.dart index 0f631fbba..59584d23a 100644 --- a/lib/common/widgets/page/page_view.dart +++ b/lib/common/widgets/page/page_view.dart @@ -16,8 +16,10 @@ import 'package:flutter/material.dart' hide Scrollable, ScrollableState; import 'package:flutter/rendering.dart'; class _ForceImplicitScrollPhysics extends ScrollPhysics { - const _ForceImplicitScrollPhysics( - {required this.allowImplicitScrolling, super.parent}); + const _ForceImplicitScrollPhysics({ + required this.allowImplicitScrolling, + super.parent, + }); @override _ForceImplicitScrollPhysics applyTo(ScrollPhysics? ancestor) { @@ -160,10 +162,10 @@ class CustomPageView extends StatefulWidget { this.header, this.bgColor = Colors.transparent, }) : childrenDelegate = SliverChildBuilderDelegate( - itemBuilder, - findChildIndexCallback: findChildIndexCallback, - childCount: itemCount, - ); + itemBuilder, + findChildIndexCallback: findChildIndexCallback, + childCount: itemCount, + ); /// Creates a scrollable list that works page by page with a custom child /// model. @@ -345,8 +347,9 @@ class _CustomPageViewState extends State { case Axis.horizontal: assert(debugCheckHasDirectionality(context)); final TextDirection textDirection = Directionality.of(context); - final AxisDirection axisDirection = - textDirectionToAxisDirection(textDirection); + final AxisDirection axisDirection = textDirectionToAxisDirection( + textDirection, + ); return widget.reverse ? flipAxisDirection(axisDirection) : axisDirection; @@ -358,16 +361,18 @@ class _CustomPageViewState extends State { @override Widget build(BuildContext context) { final AxisDirection axisDirection = _getDirection(context); - final ScrollPhysics physics = _ForceImplicitScrollPhysics( - allowImplicitScrolling: widget.allowImplicitScrolling, - ).applyTo( - widget.pageSnapping - ? _kPagePhysics.applyTo( - widget.physics ?? - widget.scrollBehavior?.getScrollPhysics(context), - ) - : widget.physics ?? widget.scrollBehavior?.getScrollPhysics(context), - ); + final ScrollPhysics physics = + _ForceImplicitScrollPhysics( + allowImplicitScrolling: widget.allowImplicitScrolling, + ).applyTo( + widget.pageSnapping + ? _kPagePhysics.applyTo( + widget.physics ?? + widget.scrollBehavior?.getScrollPhysics(context), + ) + : widget.physics ?? + widget.scrollBehavior?.getScrollPhysics(context), + ); return NotificationListener( onNotification: (ScrollNotification notification) { @@ -392,7 +397,8 @@ class _CustomPageViewState extends State { physics: physics, restorationId: widget.restorationId, hitTestBehavior: widget.hitTestBehavior, - scrollBehavior: widget.scrollBehavior ?? + scrollBehavior: + widget.scrollBehavior ?? ScrollConfiguration.of(context).copyWith(scrollbars: false), viewportBuilder: (BuildContext context, ViewportOffset position) { return Viewport( @@ -424,14 +430,25 @@ class _CustomPageViewState extends State { ..add(EnumProperty('scrollDirection', widget.scrollDirection)) ..add(FlagProperty('reverse', value: widget.reverse, ifTrue: 'reversed')) ..add( - DiagnosticsProperty('controller', _controller, - showName: false), + DiagnosticsProperty( + 'controller', + _controller, + showName: false, + ), ) - ..add(DiagnosticsProperty('physics', widget.physics, - showName: false)) ..add( - FlagProperty('pageSnapping', - value: widget.pageSnapping, ifFalse: 'snapping disabled'), + DiagnosticsProperty( + 'physics', + widget.physics, + showName: false, + ), + ) + ..add( + FlagProperty( + 'pageSnapping', + value: widget.pageSnapping, + ifFalse: 'snapping disabled', + ), ) ..add( FlagProperty( diff --git a/lib/common/widgets/page/scrollable.dart b/lib/common/widgets/page/scrollable.dart index da2e1f475..95254c18f 100644 --- a/lib/common/widgets/page/scrollable.dart +++ b/lib/common/widgets/page/scrollable.dart @@ -356,8 +356,8 @@ class CustomScrollable extends StatefulWidget { static CustomScrollableState? maybeOf(BuildContext context, {Axis? axis}) { // This is the context that will need to establish the dependency. final BuildContext originalContext = context; - InheritedElement? element = - context.getElementForInheritedWidgetOfExactType<_ScrollableScope>(); + InheritedElement? element = context + .getElementForInheritedWidgetOfExactType<_ScrollableScope>(); while (element != null) { final CustomScrollableState scrollable = (element.widget as _ScrollableScope).scrollable; @@ -368,8 +368,8 @@ class CustomScrollable extends StatefulWidget { return scrollable; } context = scrollable.context; - element = - context.getElementForInheritedWidgetOfExactType<_ScrollableScope>(); + element = context + .getElementForInheritedWidgetOfExactType<_ScrollableScope>(); } return null; } @@ -451,10 +451,12 @@ class CustomScrollable extends StatefulWidget { /// /// If there is no [CustomScrollable] in the widget tree above the [context], this /// method returns false. - static bool recommendDeferredLoadingForContext(BuildContext context, - {Axis? axis}) { - _ScrollableScope? widget = - context.getInheritedWidgetOfExactType<_ScrollableScope>(); + static bool recommendDeferredLoadingForContext( + BuildContext context, { + Axis? axis, + }) { + _ScrollableScope? widget = context + .getInheritedWidgetOfExactType<_ScrollableScope>(); while (widget != null) { if (axis == null || axisDirectionToAxis(widget.scrollable.axisDirection) == axis) { @@ -521,8 +523,11 @@ class CustomScrollable extends StatefulWidget { // Enable Scrollable.of() to work as if ScrollableState was an inherited widget. // ScrollableState.build() always rebuilds its _ScrollableScope. class _ScrollableScope extends InheritedWidget { - const _ScrollableScope( - {required this.scrollable, required this.position, required super.child}); + const _ScrollableScope({ + required this.scrollable, + required this.position, + required super.child, + }); final CustomScrollableState scrollable; final ScrollPosition position; @@ -566,11 +571,11 @@ class CustomScrollableState extends State /// Used by [EdgeDraggingAutoScroller] to progress the position forward when a /// drag gesture reaches the edge of the [Viewport]. Offset get deltaToScrollOrigin => switch (axisDirection) { - AxisDirection.up => Offset(0, -position.pixels), - AxisDirection.down => Offset(0, position.pixels), - AxisDirection.left => Offset(-position.pixels, 0), - AxisDirection.right => Offset(position.pixels, 0), - }; + AxisDirection.up => Offset(0, -position.pixels), + AxisDirection.down => Offset(0, position.pixels), + AxisDirection.left => Offset(-position.pixels, 0), + AxisDirection.right => Offset(position.pixels, 0), + }; ScrollController get _effectiveScrollController => widget.controller ?? _fallbackScrollController!; @@ -618,7 +623,10 @@ class CustomScrollableState extends State } _position = _effectiveScrollController.createScrollPosition( - _physics!, this, oldPosition); + _physics!, + this, + oldPosition, + ); assert(_position != null); _effectiveScrollController.attach(position); } @@ -629,8 +637,10 @@ class CustomScrollableState extends State registerForRestoration(_persistedScrollOffset, 'offset'); assert(_position != null); if (_persistedScrollOffset.value != null) { - position.restoreOffset(_persistedScrollOffset.value!, - initialRestore: initialRestore); + position.restoreOffset( + _persistedScrollOffset.value!, + initialRestore: initialRestore, + ); } } @@ -655,15 +665,18 @@ class CustomScrollableState extends State vsync: this, reverseDuration: const Duration(milliseconds: 500), ); - _anim = Tween(begin: Offset.zero, end: const Offset(0, 1)) - .animate(_animController); + _anim = Tween( + begin: Offset.zero, + end: const Offset(0, 1), + ).animate(_animController); } @protected @override void didChangeDependencies() { _mediaQueryGestureSettings = MediaQuery.maybeGestureSettingsOf(context); - _devicePixelRatio = MediaQuery.maybeDevicePixelRatioOf(context) ?? + _devicePixelRatio = + MediaQuery.maybeDevicePixelRatioOf(context) ?? View.of(context).devicePixelRatio; _updatePosition(); super.didChangeDependencies(); @@ -680,7 +693,8 @@ class CustomScrollableState extends State } ScrollPhysics? newPhysics = widget.physics ?? widget.scrollBehavior?.getScrollPhysics(context); - ScrollPhysics? oldPhysics = oldWidget.physics ?? + ScrollPhysics? oldPhysics = + oldWidget.physics ?? oldWidget.scrollBehavior?.getScrollPhysics(context); do { if (newPhysics?.runtimeType != oldPhysics?.runtimeType) { @@ -791,64 +805,70 @@ class CustomScrollableState extends State switch (widget.axis) { case Axis.vertical: _gestureRecognizers = { - VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers< - VerticalDragGestureRecognizer>( - () => VerticalDragGestureRecognizer( - supportedDevices: _configuration.dragDevices), - (VerticalDragGestureRecognizer instance) { - instance - ..onDown = _handleDragDown - ..onStart = _handleDragStart - ..onUpdate = _handleDragUpdate - ..onEnd = _handleDragEnd - ..onCancel = _handleDragCancel - ..minFlingDistance = _physics?.minFlingDistance - ..minFlingVelocity = _physics?.minFlingVelocity - ..maxFlingVelocity = _physics?.maxFlingVelocity - ..velocityTrackerBuilder = - _configuration.velocityTrackerBuilder(context) - ..dragStartBehavior = widget.dragStartBehavior - ..multitouchDragStrategy = - _configuration.getMultitouchDragStrategy(context) - ..gestureSettings = _mediaQueryGestureSettings - ..supportedDevices = _configuration.dragDevices; - }, - ), + VerticalDragGestureRecognizer: + GestureRecognizerFactoryWithHandlers< + VerticalDragGestureRecognizer + >( + () => VerticalDragGestureRecognizer( + supportedDevices: _configuration.dragDevices, + ), + (VerticalDragGestureRecognizer instance) { + instance + ..onDown = _handleDragDown + ..onStart = _handleDragStart + ..onUpdate = _handleDragUpdate + ..onEnd = _handleDragEnd + ..onCancel = _handleDragCancel + ..minFlingDistance = _physics?.minFlingDistance + ..minFlingVelocity = _physics?.minFlingVelocity + ..maxFlingVelocity = _physics?.maxFlingVelocity + ..velocityTrackerBuilder = _configuration + .velocityTrackerBuilder(context) + ..dragStartBehavior = widget.dragStartBehavior + ..multitouchDragStrategy = _configuration + .getMultitouchDragStrategy(context) + ..gestureSettings = _mediaQueryGestureSettings + ..supportedDevices = _configuration.dragDevices; + }, + ), }; case Axis.horizontal: _gestureRecognizers = { HorizontalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers< - HorizontalDragGestureRecognizer>( - () => HorizontalDragGestureRecognizer( - supportedDevices: _configuration.dragDevices), - (HorizontalDragGestureRecognizer instance) { - instance - ..onDown = _handleDragDown - ..onStart = _handleDragStart - ..onUpdate = _handleDragUpdate - ..onEnd = _handleDragEnd - ..onCancel = _handleDragCancel - ..minFlingDistance = _physics?.minFlingDistance - ..minFlingVelocity = _physics?.minFlingVelocity - ..maxFlingVelocity = _physics?.maxFlingVelocity - ..velocityTrackerBuilder = - _configuration.velocityTrackerBuilder(context) - ..dragStartBehavior = widget.dragStartBehavior - ..multitouchDragStrategy = - _configuration.getMultitouchDragStrategy(context) - ..gestureSettings = _mediaQueryGestureSettings - ..supportedDevices = _configuration.dragDevices; - }, - ), + HorizontalDragGestureRecognizer + >( + () => HorizontalDragGestureRecognizer( + supportedDevices: _configuration.dragDevices, + ), + (HorizontalDragGestureRecognizer instance) { + instance + ..onDown = _handleDragDown + ..onStart = _handleDragStart + ..onUpdate = _handleDragUpdate + ..onEnd = _handleDragEnd + ..onCancel = _handleDragCancel + ..minFlingDistance = _physics?.minFlingDistance + ..minFlingVelocity = _physics?.minFlingVelocity + ..maxFlingVelocity = _physics?.maxFlingVelocity + ..velocityTrackerBuilder = _configuration + .velocityTrackerBuilder(context) + ..dragStartBehavior = widget.dragStartBehavior + ..multitouchDragStrategy = _configuration + .getMultitouchDragStrategy(context) + ..gestureSettings = _mediaQueryGestureSettings + ..supportedDevices = _configuration.dragDevices; + }, + ), }; } } _lastCanDrag = value; _lastAxisDirection = widget.axis; if (_gestureDetectorKey.currentState != null) { - _gestureDetectorKey.currentState! - .replaceGestureRecognizers(_gestureRecognizers); + _gestureDetectorKey.currentState!.replaceGestureRecognizers( + _gestureRecognizers, + ); } } @@ -860,8 +880,9 @@ class CustomScrollableState extends State } _shouldIgnorePointer = value; if (_ignorePointerKey.currentContext != null) { - final RenderIgnorePointer renderBox = _ignorePointerKey.currentContext! - .findRenderObject()! as RenderIgnorePointer; + final RenderIgnorePointer renderBox = + _ignorePointerKey.currentContext!.findRenderObject()! + as RenderIgnorePointer; renderBox.ignoring = _shouldIgnorePointer; } } @@ -999,8 +1020,8 @@ class CustomScrollableState extends State double _pointerSignalEventDelta(PointerScrollEvent event) { final Set pressed = HardwareKeyboard.instance.logicalKeysPressed; - final bool flipAxes = pressed - .any(_configuration.pointerAxisModifiers.contains) && + final bool flipAxes = + pressed.any(_configuration.pointerAxisModifiers.contains) && // Axes are only flipped for physical mouse wheel input. // On some platforms, like web, trackpad input is handled through pointer // signals, but should not be included in this axis modifying behavior. @@ -1027,12 +1048,15 @@ class CustomScrollableState extends State return; } final double delta = _pointerSignalEventDelta(event); - final double targetScrollOffset = - _targetScrollOffsetForPointerScroll(delta); + final double targetScrollOffset = _targetScrollOffsetForPointerScroll( + delta, + ); // Only express interest in the event if it would actually result in a scroll. if (delta != 0.0 && targetScrollOffset != position.pixels) { - GestureBinding.instance.pointerSignalResolver - .register(event, _handlePointerScroll); + GestureBinding.instance.pointerSignalResolver.register( + event, + _handlePointerScroll, + ); return; } // The `event` won't result in a scroll, so allow the platform to trigger @@ -1047,18 +1071,21 @@ class CustomScrollableState extends State void _handlePointerScroll(PointerEvent event) { assert(event is PointerScrollEvent); final double delta = _pointerSignalEventDelta(event as PointerScrollEvent); - final double targetScrollOffset = - _targetScrollOffsetForPointerScroll(delta); + final double targetScrollOffset = _targetScrollOffsetForPointerScroll( + delta, + ); if (delta != 0.0 && targetScrollOffset != position.pixels) { position.pointerScroll(delta); } } bool _handleScrollMetricsNotification( - ScrollMetricsNotification notification) { + ScrollMetricsNotification notification, + ) { if (notification.depth == 0) { - final RenderObject? scrollSemanticsRenderObject = - _scrollSemanticsKey.currentContext?.findRenderObject(); + final RenderObject? scrollSemanticsRenderObject = _scrollSemanticsKey + .currentContext + ?.findRenderObject(); if (scrollSemanticsRenderObject != null) { scrollSemanticsRenderObject.markNeedsSemanticsUpdate(); } @@ -1267,13 +1294,14 @@ class _ScrollableSelectionHandlerState /// selectable. class _ScrollableSelectionContainerDelegate extends MultiSelectableSelectionContainerDelegate { - _ScrollableSelectionContainerDelegate( - {required this.state, required ScrollPosition position}) - : _position = position, - _autoScroller = EdgeDraggingAutoScroller( - state, - velocityScalar: _kDefaultSelectToScrollVelocityScalar, - ) { + _ScrollableSelectionContainerDelegate({ + required this.state, + required ScrollPosition position, + }) : _position = position, + _autoScroller = EdgeDraggingAutoScroller( + state, + velocityScalar: _kDefaultSelectToScrollVelocityScalar, + ) { _position.addListener(_scheduleLayoutChange); } @@ -1367,13 +1395,15 @@ class _ScrollableSelectionContainerDelegate if (_currentDragEndRelatedToOrigin == null && _currentDragStartRelatedToOrigin == null) { assert(!_selectionStartsInScrollable); - _selectionStartsInScrollable = - _globalPositionInScrollable(event.globalPosition); + _selectionStartsInScrollable = _globalPositionInScrollable( + event.globalPosition, + ); } final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); if (event.type == SelectionEventType.endEdgeUpdate) { - _currentDragEndRelatedToOrigin = - _inferPositionRelatedToOrigin(event.globalPosition); + _currentDragEndRelatedToOrigin = _inferPositionRelatedToOrigin( + event.globalPosition, + ); final Offset endOffset = _currentDragEndRelatedToOrigin!.translate( -deltaToOrigin.dx, -deltaToOrigin.dy, @@ -1383,8 +1413,9 @@ class _ScrollableSelectionContainerDelegate granularity: event.granularity, ); } else { - _currentDragStartRelatedToOrigin = - _inferPositionRelatedToOrigin(event.globalPosition); + _currentDragStartRelatedToOrigin = _inferPositionRelatedToOrigin( + event.globalPosition, + ); final Offset startOffset = _currentDragStartRelatedToOrigin!.translate( -deltaToOrigin.dx, -deltaToOrigin.dy, @@ -1430,7 +1461,8 @@ class _ScrollableSelectionContainerDelegate } final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); return box.localToGlobal( - localPosition.translate(deltaToOrigin.dx, deltaToOrigin.dy)); + localPosition.translate(deltaToOrigin.dx, deltaToOrigin.dy), + ); } /// Infers the [_currentDragStartRelatedToOrigin] and @@ -1453,8 +1485,8 @@ class _ScrollableSelectionContainerDelegate selectables[currentSelectionStartIndex].value; assert(geometry.hasSelection); final SelectionPoint start = geometry.startSelectionPoint!; - final Matrix4 childTransform = - selectables[currentSelectionStartIndex].getTransformTo(box); + final Matrix4 childTransform = selectables[currentSelectionStartIndex] + .getTransformTo(box); final Offset localDragStart = MatrixUtils.transformPoint( childTransform, start.localPosition + Offset(0, -start.lineHeight / 2), @@ -1470,8 +1502,8 @@ class _ScrollableSelectionContainerDelegate selectables[currentSelectionEndIndex].value; assert(geometry.hasSelection); final SelectionPoint end = geometry.endSelectionPoint!; - final Matrix4 childTransform = - selectables[currentSelectionEndIndex].getTransformTo(box); + final Matrix4 childTransform = selectables[currentSelectionEndIndex] + .getTransformTo(box); final Offset localDragEnd = MatrixUtils.transformPoint( childTransform, end.localPosition + Offset(0, -end.lineHeight / 2), @@ -1488,7 +1520,8 @@ class _ScrollableSelectionContainerDelegate assert(!_selectionStartsInScrollable); final SelectionResult result = super.handleSelectAll(event); assert( - (currentSelectionStartIndex == -1) == (currentSelectionEndIndex == -1)); + (currentSelectionStartIndex == -1) == (currentSelectionEndIndex == -1), + ); if (currentSelectionStartIndex != -1) { _updateDragLocationsFromGeometries(); } @@ -1497,8 +1530,9 @@ class _ScrollableSelectionContainerDelegate @override SelectionResult handleSelectWord(SelectWordSelectionEvent event) { - _selectionStartsInScrollable = - _globalPositionInScrollable(event.globalPosition); + _selectionStartsInScrollable = _globalPositionInScrollable( + event.globalPosition, + ); final SelectionResult result = super.handleSelectWord(event); _updateDragLocationsFromGeometries(); return result; @@ -1506,13 +1540,16 @@ class _ScrollableSelectionContainerDelegate @override SelectionResult handleGranularlyExtendSelection( - GranularlyExtendSelectionEvent event) { + GranularlyExtendSelectionEvent event, + ) { final SelectionResult result = super.handleGranularlyExtendSelection(event); // The selection geometry may not have the accurate offset for the edges // that are outside of the viewport whose transform may not be valid. Only // the edge this event is updating is sure to be accurate. _updateDragLocationsFromGeometries( - forceUpdateStart: !event.isEnd, forceUpdateEnd: event.isEnd); + forceUpdateStart: !event.isEnd, + forceUpdateEnd: event.isEnd, + ); if (_selectionStartsInScrollable) { _jumpToEdge(event.isEnd); } @@ -1521,14 +1558,18 @@ class _ScrollableSelectionContainerDelegate @override SelectionResult handleDirectionallyExtendSelection( - DirectionallyExtendSelectionEvent event) { - final SelectionResult result = - super.handleDirectionallyExtendSelection(event); + DirectionallyExtendSelectionEvent event, + ) { + final SelectionResult result = super.handleDirectionallyExtendSelection( + event, + ); // The selection geometry may not have the accurate offset for the edges // that are outside of the viewport whose transform may not be valid. Only // the edge this event is updating is sure to be accurate. _updateDragLocationsFromGeometries( - forceUpdateStart: !event.isEnd, forceUpdateEnd: event.isEnd); + forceUpdateStart: !event.isEnd, + forceUpdateEnd: event.isEnd, + ); if (_selectionStartsInScrollable) { _jumpToEdge(event.isEnd); } @@ -1643,7 +1684,9 @@ class _ScrollableSelectionContainerDelegate @override SelectionResult dispatchSelectionEventToChild( - Selectable selectable, SelectionEvent event) { + Selectable selectable, + SelectionEvent event, + ) { switch (event.type) { case SelectionEventType.startEdgeUpdate: _selectableStartEdgeUpdateRecords[selectable] = state.position.pixels; @@ -1702,7 +1745,8 @@ class _ScrollableSelectionContainerDelegate -deltaToOrigin.dy, ); selectable.dispatchSelectionEvent( - SelectionEdgeUpdateEvent.forEnd(globalPosition: endOffset)); + SelectionEdgeUpdateEvent.forEnd(globalPosition: endOffset), + ); // Make sure we track that we have synthesized an end event for this selectable, // so we don't synthesize events unnecessarily. _selectableEndEdgeUpdateRecords[selectable] = state.position.pixels; @@ -1769,7 +1813,9 @@ class _ScrollSemantics extends SingleChildRenderObjectWidget { @override void updateRenderObject( - BuildContext context, _RenderScrollSemantics renderObject) { + BuildContext context, + _RenderScrollSemantics renderObject, + ) { renderObject ..allowImplicitScrolling = allowImplicitScrolling ..axis = axis @@ -1785,10 +1831,10 @@ class _RenderScrollSemantics extends RenderProxyBox { required this.axis, required int? semanticChildCount, RenderBox? child, - }) : _position = position, - _allowImplicitScrolling = allowImplicitScrolling, - _semanticChildCount = semanticChildCount, - super(child) { + }) : _position = position, + _allowImplicitScrolling = allowImplicitScrolling, + _semanticChildCount = semanticChildCount, + super(child) { position.addListener(markNeedsSemanticsUpdate); } @@ -1887,8 +1933,10 @@ class _RenderScrollSemantics extends RenderProxyBox { } config.scrollIndex = firstVisibleIndex; node.updateWith(config: null, childrenInInversePaintOrder: excluded); - _innerNode! - .updateWith(config: config, childrenInInversePaintOrder: included); + _innerNode!.updateWith( + config: config, + childrenInInversePaintOrder: included, + ); } @override @@ -2019,8 +2067,10 @@ class EdgeDraggingAutoScroller { /// previous dragTarget to the new value and continues scrolling if necessary. void startAutoScrollIfNecessary(Rect dragTarget) { final Offset deltaToOrigin = scrollable.deltaToScrollOrigin; - _dragTargetRelatedToScrollOrigin = - dragTarget.translate(deltaToOrigin.dx, deltaToOrigin.dy); + _dragTargetRelatedToScrollOrigin = dragTarget.translate( + deltaToOrigin.dx, + deltaToOrigin.dy, + ); if (_scrolling) { // The change will be picked up in the next scroll. return; @@ -2040,7 +2090,11 @@ class EdgeDraggingAutoScroller { final Rect globalRect = MatrixUtils.transformRect( scrollRenderBox.getTransformTo(null), Rect.fromLTWH( - 0, 0, scrollRenderBox.size.width, scrollRenderBox.size.height), + 0, + 0, + scrollRenderBox.size.width, + scrollRenderBox.size.height, + ), ); assert( globalRect.size.width >= _dragTargetRelatedToScrollOrigin.size.width && @@ -2053,10 +2107,14 @@ class EdgeDraggingAutoScroller { const double overDragMax = 20.0; final Offset deltaToOrigin = scrollable.deltaToScrollOrigin; - final Offset viewportOrigin = - globalRect.topLeft.translate(deltaToOrigin.dx, deltaToOrigin.dy); - final double viewportStart = - _offsetExtent(viewportOrigin, _scrollDirection); + final Offset viewportOrigin = globalRect.topLeft.translate( + deltaToOrigin.dx, + deltaToOrigin.dy, + ); + final double viewportStart = _offsetExtent( + viewportOrigin, + _scrollDirection, + ); final double viewportEnd = viewportStart + _sizeExtent(globalRect.size, _scrollDirection); @@ -2080,8 +2138,10 @@ class EdgeDraggingAutoScroller { ); } else if (proxyStart < viewportStart && scrollable.position.pixels < scrollable.position.maxScrollExtent) { - final double overDrag = - math.min(viewportStart - proxyStart, overDragMax); + final double overDrag = math.min( + viewportStart - proxyStart, + overDragMax, + ); newOffset = math.min( scrollable.position.maxScrollExtent, scrollable.position.pixels + overDrag, @@ -2091,8 +2151,10 @@ class EdgeDraggingAutoScroller { case AxisDirection.down: if (proxyStart < viewportStart && scrollable.position.pixels > scrollable.position.minScrollExtent) { - final double overDrag = - math.min(viewportStart - proxyStart, overDragMax); + final double overDrag = math.min( + viewportStart - proxyStart, + overDragMax, + ); newOffset = math.max( scrollable.position.minScrollExtent, scrollable.position.pixels - overDrag, @@ -2113,10 +2175,14 @@ class EdgeDraggingAutoScroller { _scrolling = false; return; } - final Duration duration = - Duration(milliseconds: (1000 / velocityScalar).round()); - await scrollable.position - .animateTo(newOffset, duration: duration, curve: Curves.linear); + final Duration duration = Duration( + milliseconds: (1000 / velocityScalar).round(), + ); + await scrollable.position.animateTo( + newOffset, + duration: duration, + curve: Curves.linear, + ); onScrollViewScrolled?.call(); if (_scrolling) { await _scroll(); diff --git a/lib/common/widgets/page/tabs.dart b/lib/common/widgets/page/tabs.dart index 57e5bd8e3..cd567232d 100644 --- a/lib/common/widgets/page/tabs.dart +++ b/lib/common/widgets/page/tabs.dart @@ -132,11 +132,17 @@ class _CustomTabBarViewState extends State { _warpUnderwayCount -= 1; } - Future _animateToPage(int page, - {required Duration duration, required Curve curve}) async { + Future _animateToPage( + int page, { + required Duration duration, + required Curve curve, + }) async { _warpUnderwayCount += 1; - await _pageController! - .animateToPage(page, duration: duration, curve: curve); + await _pageController!.animateToPage( + page, + duration: duration, + curve: curve, + ); _warpUnderwayCount -= 1; } @@ -231,8 +237,11 @@ class _CustomTabBarViewState extends State { if (duration == Duration.zero) { _jumpToPage(_currentIndex!); } else { - await _animateToPage(_currentIndex!, - duration: duration, curve: Curves.ease); + await _animateToPage( + _currentIndex!, + duration: duration, + curve: Curves.ease, + ); } if (mounted) { setState(() { @@ -269,8 +278,11 @@ class _CustomTabBarViewState extends State { if (duration == Duration.zero) { _jumpToPage(_currentIndex!); } else { - await _animateToPage(_currentIndex!, - duration: duration, curve: Curves.ease); + await _animateToPage( + _currentIndex!, + duration: duration, + curve: Curves.ease, + ); } if (mounted) { @@ -281,8 +293,11 @@ class _CustomTabBarViewState extends State { } void _syncControllerOffset() { - _controller!.offset = - clampDouble(_pageController!.page! - _controller!.index, -1.0, 1.0); + _controller!.offset = clampDouble( + _pageController!.page! - _controller!.index, + -1.0, + 1.0, + ); } // Called when the PageView scrolls diff --git a/lib/common/widgets/pendant_avatar.dart b/lib/common/widgets/pendant_avatar.dart index ca7e5b4d1..316f5d8c3 100644 --- a/lib/common/widgets/pendant_avatar.dart +++ b/lib/common/widgets/pendant_avatar.dart @@ -27,16 +27,16 @@ class PendantAvatar extends StatelessWidget { this.garbPendantImage, this.roomId, this.onTap, - }) : _badgeType = officialType == null || officialType < 0 - ? isVip == true - ? BadgeType.vip - : BadgeType.none - : officialType == 0 - ? BadgeType.person - : officialType == 1 - ? BadgeType.institution - : BadgeType.none, - badgeSize = badgeSize ?? size / 3; + }) : _badgeType = officialType == null || officialType < 0 + ? isVip == true + ? BadgeType.vip + : BadgeType.none + : officialType == 0 + ? BadgeType.person + : officialType == 1 + ? BadgeType.institution + : BadgeType.none, + badgeSize = badgeSize ?? size / 3; static bool showDynDecorate = Pref.showDynDecorate; @@ -56,7 +56,8 @@ class PendantAvatar extends StatelessWidget { ), if (showDynDecorate && !garbPendantImage.isNullOrEmpty) Positioned( - top: -0.375 * + top: + -0.375 * (size == 80 ? size - 4 : size), // -(size * 1.75 - size) / 2 child: IgnorePointer( child: CachedNetworkImage( @@ -133,27 +134,29 @@ class PendantAvatar extends StatelessWidget { Widget _buildBadge(ColorScheme colorScheme) { final child = switch (_badgeType) { BadgeType.vip => Image.asset( - 'assets/images/big-vip.png', - height: badgeSize, - semanticLabel: _badgeType.desc, - ), + 'assets/images/big-vip.png', + height: badgeSize, + semanticLabel: _badgeType.desc, + ), _ => Icon( - Icons.offline_bolt, - color: _badgeType.color, - size: badgeSize, - semanticLabel: _badgeType.desc, - ), + Icons.offline_bolt, + color: _badgeType.color, + size: badgeSize, + semanticLabel: _badgeType.desc, + ), }; return Positioned( - right: 0, - bottom: 0, - child: IgnorePointer( - child: DecoratedBox( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: colorScheme.surface, - ), - child: child), - )); + right: 0, + bottom: 0, + child: IgnorePointer( + child: DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: colorScheme.surface, + ), + child: child, + ), + ), + ); } } diff --git a/lib/common/widgets/progress_bar/audio_video_progress_bar.dart b/lib/common/widgets/progress_bar/audio_video_progress_bar.dart index a284e365b..72b8265e7 100644 --- a/lib/common/widgets/progress_bar/audio_video_progress_bar.dart +++ b/lib/common/widgets/progress_bar/audio_video_progress_bar.dart @@ -326,16 +326,34 @@ class ProgressBar extends LeafRenderObjectWidget { ..add(StringProperty('progress', progress.toString())) ..add(StringProperty('total', total.toString())) ..add(StringProperty('buffered', buffered.toString())) - ..add(ObjectFlagProperty>('onSeek', onSeek, - ifNull: 'unimplemented')) - ..add(ObjectFlagProperty( - 'onDragStart', onDragStart, - ifNull: 'unimplemented')) - ..add(ObjectFlagProperty( - 'onDragUpdate', onDragUpdate, - ifNull: 'unimplemented')) - ..add(ObjectFlagProperty('onDragEnd', onDragEnd, - ifNull: 'unimplemented')) + ..add( + ObjectFlagProperty>( + 'onSeek', + onSeek, + ifNull: 'unimplemented', + ), + ) + ..add( + ObjectFlagProperty( + 'onDragStart', + onDragStart, + ifNull: 'unimplemented', + ), + ) + ..add( + ObjectFlagProperty( + 'onDragUpdate', + onDragUpdate, + ifNull: 'unimplemented', + ), + ) + ..add( + ObjectFlagProperty( + 'onDragEnd', + onDragEnd, + ifNull: 'unimplemented', + ), + ) ..add(DoubleProperty('barHeight', barHeight)) ..add(ColorProperty('baseBarColor', baseBarColor)) ..add(ColorProperty('progressBarColor', progressBarColor)) @@ -386,7 +404,8 @@ class ThumbDragDetails { final Offset localPosition; @override - String toString() => '${objectRuntimeType(this, 'ThumbDragDetails')}(' + String toString() => + '${objectRuntimeType(this, 'ThumbDragDetails')}(' 'time: $timeStamp, ' 'global: $globalPosition, ' 'local: $localPosition)'; @@ -431,27 +450,27 @@ class _RenderProgressBar extends RenderBox { TextStyle? timeLabelTextStyle, double timeLabelPadding = 0.0, double textScaleFactor = 1.0, - }) : _total = total, - _buffered = buffered, - _onSeek = onSeek, - _onDragStartUserCallback = onDragStart, - _onDragUpdateUserCallback = onDragUpdate, - _onDragEndUserCallback = onDragEnd, - _barHeight = barHeight, - _baseBarColor = baseBarColor, - _progressBarColor = progressBarColor, - _bufferedBarColor = bufferedBarColor, - _barCapShape = barCapShape, - _thumbRadius = thumbRadius, - _thumbColor = thumbColor, - _thumbGlowColor = thumbGlowColor, - _thumbGlowRadius = thumbGlowRadius, - _thumbCanPaintOutsideBar = thumbCanPaintOutsideBar, - _timeLabelLocation = timeLabelLocation, - _timeLabelType = timeLabelType, - _timeLabelTextStyle = timeLabelTextStyle, - _timeLabelPadding = timeLabelPadding, - _textScaleFactor = textScaleFactor { + }) : _total = total, + _buffered = buffered, + _onSeek = onSeek, + _onDragStartUserCallback = onDragStart, + _onDragUpdateUserCallback = onDragUpdate, + _onDragEndUserCallback = onDragEnd, + _barHeight = barHeight, + _baseBarColor = baseBarColor, + _progressBarColor = progressBarColor, + _bufferedBarColor = bufferedBarColor, + _barCapShape = barCapShape, + _thumbRadius = thumbRadius, + _thumbColor = thumbColor, + _thumbGlowColor = thumbGlowColor, + _thumbGlowRadius = thumbGlowRadius, + _thumbCanPaintOutsideBar = thumbCanPaintOutsideBar, + _timeLabelLocation = timeLabelLocation, + _timeLabelType = timeLabelType, + _timeLabelTextStyle = timeLabelTextStyle, + _timeLabelPadding = timeLabelPadding, + _textScaleFactor = textScaleFactor { _drag = _EagerHorizontalDragGestureRecognizer() ..onStart = _onDragStart ..onUpdate = _onDragUpdate @@ -490,11 +509,13 @@ class _RenderProgressBar extends RenderBox { } _userIsDraggingThumb = true; _updateThumbPosition(details.localPosition); - onDragStart?.call(ThumbDragDetails( - timeStamp: _currentThumbDuration(), - globalPosition: details.globalPosition, - localPosition: details.localPosition, - )); + onDragStart?.call( + ThumbDragDetails( + timeStamp: _currentThumbDuration(), + globalPosition: details.globalPosition, + localPosition: details.localPosition, + ), + ); } void _onDragUpdate(DragUpdateDetails details) { @@ -502,11 +523,13 @@ class _RenderProgressBar extends RenderBox { return; } _updateThumbPosition(details.localPosition); - onDragUpdate?.call(ThumbDragDetails( - timeStamp: _currentThumbDuration(), - globalPosition: details.globalPosition, - localPosition: details.localPosition, - )); + onDragUpdate?.call( + ThumbDragDetails( + timeStamp: _currentThumbDuration(), + globalPosition: details.globalPosition, + localPosition: details.localPosition, + ), + ); } void _onDragEnd(DragEndDetails details) { @@ -620,10 +643,10 @@ class _RenderProgressBar extends RenderBox { TextPainter _layoutText(String text) { TextPainter textPainter = TextPainter( - text: TextSpan(text: text, style: _timeLabelTextStyle), - textDirection: TextDirection.ltr, - textScaler: TextScaler.linear(textScaleFactor)) - ..layout(minWidth: 0, maxWidth: double.infinity); + text: TextSpan(text: text, style: _timeLabelTextStyle), + textDirection: TextDirection.ltr, + textScaler: TextScaler.linear(textScaleFactor), + )..layout(minWidth: 0, maxWidth: double.infinity); return textPainter; } @@ -966,8 +989,9 @@ class _RenderProgressBar extends RenderBox { _rightTimeLabel().paint(canvas, rightLabelOffset); // progress bar - final barDy = - (isLabelBelow) ? 0.0 : _leftLabelSize.height + _timeLabelPadding; + final barDy = (isLabelBelow) + ? 0.0 + : _leftLabelSize.height + _timeLabelPadding; _drawProgressBar(canvas, Offset(0, barDy), Size(barWidth, barHeight)); } @@ -992,7 +1016,8 @@ class _RenderProgressBar extends RenderBox { // progress bar final leftLabelWidth = leftLabelSize.width; final barHeight = _heightWhenNoLabels(); - final barWidth = size.width - + final barWidth = + size.width - 2 * _defaultSidePadding - 2 * _timeLabelPadding - leftLabelWidth - @@ -1050,11 +1075,12 @@ class _RenderProgressBar extends RenderBox { ); } - void _drawBar( - {required Canvas canvas, - required Size availableSize, - required double widthProportion, - required Color color}) { + void _drawBar({ + required Canvas canvas, + required Size availableSize, + required double widthProportion, + required Color color, + }) { final strokeCap = (_barCapShape == BarCapShape.round) ? StrokeCap.round : StrokeCap.square; @@ -1094,8 +1120,9 @@ class _RenderProgressBar extends RenderBox { } String _getTimeString(Duration time) { - final minutes = - time.inMinutes.remainder(Duration.minutesPerHour).toString(); + final minutes = time.inMinutes + .remainder(Duration.minutesPerHour) + .toString(); final seconds = time.inSeconds .remainder(Duration.secondsPerMinute) .toString() @@ -1112,15 +1139,14 @@ class _RenderProgressBar extends RenderBox { // description config ..textDirection = TextDirection.ltr - ..label = '进度条' //'Progress bar'; + ..label = + '进度条' //'Progress bar'; ..value = '${(_thumbValue * 100).round()}%' - // increase action ..onIncrease = increaseAction; final increased = _thumbValue + _semanticActionUnit; config ..increasedValue = '${((increased).clamp(0.0, 1.0) * 100).round()}%' - // decrease action ..onDecrease = decreaseAction; final decreased = _thumbValue - _semanticActionUnit; diff --git a/lib/common/widgets/progress_bar/segment_progress_bar.dart b/lib/common/widgets/progress_bar/segment_progress_bar.dart index 697f32973..a8e91f2ff 100644 --- a/lib/common/widgets/progress_bar/segment_progress_bar.dart +++ b/lib/common/widgets/progress_bar/segment_progress_bar.dart @@ -43,7 +43,8 @@ class SegmentProgressBar extends CustomPainter { if (item.title != null) { double fontSize = 10; - _defHeight ??= (TextPainter( + _defHeight ??= + (TextPainter( text: TextSpan( text: item.title, style: TextStyle( @@ -51,23 +52,21 @@ class SegmentProgressBar extends CustomPainter { ), ), textDirection: TextDirection.ltr, - )..layout()) - .height + + )..layout()).height + 2; TextPainter getTextPainter() => TextPainter( - text: TextSpan( - text: item.title, - style: TextStyle( - color: Colors.white, - fontSize: fontSize, - height: 1, - ), - ), - strutStyle: - StrutStyle(leading: 0, height: 1, fontSize: fontSize), - textDirection: TextDirection.ltr, - )..layout(); + text: TextSpan( + text: item.title, + style: TextStyle( + color: Colors.white, + fontSize: fontSize, + height: 1, + ), + ), + strutStyle: StrutStyle(leading: 0, height: 1, fontSize: fontSize), + textDirection: TextDirection.ltr, + )..layout(); TextPainter textPainter = getTextPainter(); @@ -107,8 +106,8 @@ class SegmentProgressBar extends CustomPainter { double textX = i == 0 ? (segmentStart - textPainter.width) / 2 : (segmentStart - prevStart - textPainter.width) / 2 + - prevStart + - 1; + prevStart + + 1; double textY = (-_defHeight! - textPainter.height) / 2; textPainter.paint(canvas, Offset(textX, textY)); } else { diff --git a/lib/common/widgets/progress_bar/video_progress_indicator.dart b/lib/common/widgets/progress_bar/video_progress_indicator.dart index 4910b6c69..9b7914443 100644 --- a/lib/common/widgets/progress_bar/video_progress_indicator.dart +++ b/lib/common/widgets/progress_bar/video_progress_indicator.dart @@ -2,18 +2,18 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:flutter/material.dart'; Widget videoProgressIndicator(double progress) => ClipRect( - clipper: ProgressClipper(), - child: ClipRRect( - borderRadius: const BorderRadius.only( - bottomLeft: StyleString.imgRadius, - bottomRight: StyleString.imgRadius, - ), - child: LinearProgressIndicator( - minHeight: 10, - value: progress, - ), - ), - ); + clipper: ProgressClipper(), + child: ClipRRect( + borderRadius: const BorderRadius.only( + bottomLeft: StyleString.imgRadius, + bottomRight: StyleString.imgRadius, + ), + child: LinearProgressIndicator( + minHeight: 10, + value: progress, + ), + ), +); class ProgressClipper extends CustomClipper { @override diff --git a/lib/common/widgets/radio_widget.dart b/lib/common/widgets/radio_widget.dart index b4a22c8c6..6a978c733 100644 --- a/lib/common/widgets/radio_widget.dart +++ b/lib/common/widgets/radio_widget.dart @@ -17,16 +17,16 @@ class RadioWidget extends StatelessWidget { }); Widget _child() => Row( - children: [ - Radio( - value: value, - groupValue: groupValue, - onChanged: onChanged, - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - Text(title), - ], - ); + children: [ + Radio( + value: value, + groupValue: groupValue, + onChanged: onChanged, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + Text(title), + ], + ); @override Widget build(BuildContext context) { diff --git a/lib/common/widgets/refresh_indicator.dart b/lib/common/widgets/refresh_indicator.dart index 4b18e9944..d72efcc40 100644 --- a/lib/common/widgets/refresh_indicator.dart +++ b/lib/common/widgets/refresh_indicator.dart @@ -167,9 +167,9 @@ class RefreshIndicator extends StatefulWidget { this.strokeWidth = RefreshProgressIndicator.defaultStrokeWidth, this.triggerMode = RefreshIndicatorTriggerMode.onEdge, this.elevation = 2.0, - }) : _indicatorType = _IndicatorType.material, - onStatusChange = null, - assert(elevation >= 0.0); + }) : _indicatorType = _IndicatorType.material, + onStatusChange = null, + assert(elevation >= 0.0); /// Creates an adaptive [RefreshIndicator] based on whether the target /// platform is iOS or macOS, following Material design's @@ -201,9 +201,9 @@ class RefreshIndicator extends StatefulWidget { this.strokeWidth = RefreshProgressIndicator.defaultStrokeWidth, this.triggerMode = RefreshIndicatorTriggerMode.onEdge, this.elevation = 2.0, - }) : _indicatorType = _IndicatorType.adaptive, - onStatusChange = null, - assert(elevation >= 0.0); + }) : _indicatorType = _IndicatorType.adaptive, + onStatusChange = null, + assert(elevation >= 0.0); /// Creates a [RefreshIndicator] with no spinner and calls `onRefresh` when /// successfully armed by a drag event. @@ -219,16 +219,16 @@ class RefreshIndicator extends StatefulWidget { this.semanticsValue, this.triggerMode = RefreshIndicatorTriggerMode.onEdge, this.elevation = 2.0, - }) : _indicatorType = _IndicatorType.noSpinner, - // The following parameters aren't used because [_IndicatorType.noSpinner] is being used, - // which involves showing no spinner, hence the following parameters are useless since - // their only use is to change the spinner's appearance. - displacement = 0.0, - edgeOffset = 0.0, - color = null, - backgroundColor = null, - strokeWidth = 0.0, - assert(elevation >= 0.0); + }) : _indicatorType = _IndicatorType.noSpinner, + // The following parameters aren't used because [_IndicatorType.noSpinner] is being used, + // which involves showing no spinner, hence the following parameters are useless since + // their only use is to change the spinner's appearance. + displacement = 0.0, + edgeOffset = 0.0, + color = null, + backgroundColor = null, + strokeWidth = 0.0, + assert(elevation >= 0.0); /// The widget below this widget in the tree. /// @@ -345,16 +345,20 @@ class RefreshIndicatorState extends State late Color _effectiveValueColor = widget.color ?? Theme.of(context).colorScheme.primary; - static final Animatable _threeQuarterTween = - Tween(begin: 0.0, end: 0.75); + static final Animatable _threeQuarterTween = Tween( + begin: 0.0, + end: 0.75, + ); static final Animatable _kDragSizeFactorLimitTween = Tween( begin: 0.0, end: _kDragSizeFactorLimit, ); - static final Animatable _oneToZeroTween = - Tween(begin: 1.0, end: 0.0); + static final Animatable _oneToZeroTween = Tween( + begin: 1.0, + end: 0.0, + ); @protected @override @@ -408,8 +412,9 @@ class RefreshIndicatorState extends State ColorTween( begin: color.withAlpha(0), end: color.withAlpha(color.alpha), - ).chain(CurveTween( - curve: const Interval(0.0, 1.0 / _kDragSizeFactorLimit))), + ).chain( + CurveTween(curve: const Interval(0.0, 1.0 / _kDragSizeFactorLimit)), + ), ); } } @@ -444,9 +449,9 @@ class RefreshIndicatorState extends State } final bool? indicatorAtTopNow = switch (notification.metrics.axisDirection) { - AxisDirection.down || AxisDirection.up => true, - AxisDirection.left || AxisDirection.right => null, - }; + AxisDirection.down || AxisDirection.up => true, + AxisDirection.left || AxisDirection.right => null, + }; if (indicatorAtTopNow != _isIndicatorAtTop) { if (_status == RefreshIndicatorStatus.drag || _status == RefreshIndicatorStatus.armed) { @@ -502,7 +507,8 @@ class RefreshIndicatorState extends State } bool _handleIndicatorNotification( - OverscrollIndicatorNotification notification) { + OverscrollIndicatorNotification notification, + ) { if (notification.depth != 0 || !notification.leading) { return false; } @@ -534,15 +540,20 @@ class RefreshIndicatorState extends State } void _checkDragOffset(double containerExtent) { - assert(_status == RefreshIndicatorStatus.drag || - _status == RefreshIndicatorStatus.armed); + assert( + _status == RefreshIndicatorStatus.drag || + _status == RefreshIndicatorStatus.armed, + ); double newValue = _dragOffset! / (containerExtent * kDragContainerExtentPercentage); if (_status == RefreshIndicatorStatus.armed) { newValue = math.max(newValue, 1.0 / _kDragSizeFactorLimit); } - _positionController.value = - clampDouble(newValue, 0.0, 1.0); // This triggers various rebuilds. + _positionController.value = clampDouble( + newValue, + 0.0, + 1.0, + ); // This triggers various rebuilds. if (_status == RefreshIndicatorStatus.drag && _valueColor.value!.alpha == _effectiveValueColor.alpha) { _status = RefreshIndicatorStatus.armed; @@ -556,19 +567,25 @@ class RefreshIndicatorState extends State // This can only be called from _show() when refreshing and // _handleScrollNotification in response to a ScrollEndNotification or // direction change. - assert(newMode == RefreshIndicatorStatus.canceled || - newMode == RefreshIndicatorStatus.done); + assert( + newMode == RefreshIndicatorStatus.canceled || + newMode == RefreshIndicatorStatus.done, + ); setState(() { _status = newMode; widget.onStatusChange?.call(_status); }); switch (_status!) { case RefreshIndicatorStatus.done: - await _scaleController.animateTo(1.0, - duration: _kIndicatorScaleDuration); + await _scaleController.animateTo( + 1.0, + duration: _kIndicatorScaleDuration, + ); case RefreshIndicatorStatus.canceled: - await _positionController.animateTo(0.0, - duration: _kIndicatorScaleDuration); + await _positionController.animateTo( + 0.0, + duration: _kIndicatorScaleDuration, + ); case RefreshIndicatorStatus.armed: case RefreshIndicatorStatus.drag: case RefreshIndicatorStatus.refresh: @@ -592,23 +609,25 @@ class RefreshIndicatorState extends State _status = RefreshIndicatorStatus.snap; widget.onStatusChange?.call(_status); _positionController - .animateTo(1.0 / _kDragSizeFactorLimit, - duration: _kIndicatorSnapDuration) + .animateTo( + 1.0 / _kDragSizeFactorLimit, + duration: _kIndicatorSnapDuration, + ) .whenComplete(() { - if (mounted && _status == RefreshIndicatorStatus.snap) { - setState(() { - // Show the indeterminate progress indicator. - _status = RefreshIndicatorStatus.refresh; - }); + if (mounted && _status == RefreshIndicatorStatus.snap) { + setState(() { + // Show the indeterminate progress indicator. + _status = RefreshIndicatorStatus.refresh; + }); - widget.onRefresh().whenComplete(() { - if (mounted && _status == RefreshIndicatorStatus.refresh) { - completer.complete(); - _dismiss(RefreshIndicatorStatus.done); + widget.onRefresh().whenComplete(() { + if (mounted && _status == RefreshIndicatorStatus.refresh) { + completer.complete(); + _dismiss(RefreshIndicatorStatus.done); + } + }); } }); - } - }); } /// Show the refresh indicator and run the refresh callback as if it had @@ -662,7 +681,7 @@ class RefreshIndicatorState extends State final bool showIndeterminateIndicator = _status == RefreshIndicatorStatus.refresh || - _status == RefreshIndicatorStatus.done; + _status == RefreshIndicatorStatus.done; return Stack( clipBehavior: Clip.none, @@ -692,22 +711,25 @@ class RefreshIndicatorState extends State builder: (BuildContext context, Widget? child) { final Widget materialIndicator = RefreshProgressIndicator( - semanticsLabel: widget.semanticsLabel ?? - MaterialLocalizations.of(context) - .refreshIndicatorSemanticLabel, - semanticsValue: widget.semanticsValue, - value: - showIndeterminateIndicator ? null : _value.value, - valueColor: _valueColor, - backgroundColor: widget.backgroundColor, - strokeWidth: widget.strokeWidth, - elevation: widget.elevation, - ); + semanticsLabel: + widget.semanticsLabel ?? + MaterialLocalizations.of( + context, + ).refreshIndicatorSemanticLabel, + semanticsValue: widget.semanticsValue, + value: showIndeterminateIndicator + ? null + : _value.value, + valueColor: _valueColor, + backgroundColor: widget.backgroundColor, + strokeWidth: widget.strokeWidth, + elevation: widget.elevation, + ); final Widget cupertinoIndicator = CupertinoActivityIndicator( - color: widget.color, - ); + color: widget.color, + ); switch (widget._indicatorType) { case _IndicatorType.material: diff --git a/lib/common/widgets/scroll_physics.dart b/lib/common/widgets/scroll_physics.dart index 8f7ba2dbf..d1faf9721 100644 --- a/lib/common/widgets/scroll_physics.dart +++ b/lib/common/widgets/scroll_physics.dart @@ -4,22 +4,20 @@ import 'package:flutter/material.dart'; Widget videoTabBarView({ required List children, TabController? controller, -}) => - TabBarView( - physics: const CustomTabBarViewClampingScrollPhysics(), - controller: controller, - children: children, - ); +}) => TabBarView( + physics: const CustomTabBarViewClampingScrollPhysics(), + controller: controller, + children: children, +); Widget tabBarView({ required List children, TabController? controller, -}) => - TabBarView( - physics: const CustomTabBarViewScrollPhysics(), - controller: controller, - children: children, - ); +}) => TabBarView( + physics: const CustomTabBarViewScrollPhysics(), + controller: controller, + children: children, +); class CustomTabBarViewScrollPhysics extends ScrollPhysics { const CustomTabBarViewScrollPhysics({super.parent}); @@ -57,7 +55,9 @@ class ReloadScrollPhysics extends AlwaysScrollableScrollPhysics { @override ReloadScrollPhysics applyTo(ScrollPhysics? ancestor) { return ReloadScrollPhysics( - parent: buildParent(ancestor), controller: controller); + parent: buildParent(ancestor), + controller: controller, + ); } @override diff --git a/lib/common/widgets/stat/stat.dart b/lib/common/widgets/stat/stat.dart index ce30c734b..94e05f456 100644 --- a/lib/common/widgets/stat/stat.dart +++ b/lib/common/widgets/stat/stat.dart @@ -18,7 +18,8 @@ class StatWidget extends StatelessWidget { @override Widget build(BuildContext context) { - Color color = this.color ?? + Color color = + this.color ?? Theme.of(context).colorScheme.outline.withValues(alpha: 0.8); return Row( spacing: 2, diff --git a/lib/common/widgets/tabs.dart b/lib/common/widgets/tabs.dart index 9345095be..7d5b9deb5 100644 --- a/lib/common/widgets/tabs.dart +++ b/lib/common/widgets/tabs.dart @@ -126,11 +126,17 @@ class _CustomTabBarViewState extends State { _warpUnderwayCount -= 1; } - Future _animateToPage(int page, - {required Duration duration, required Curve curve}) async { + Future _animateToPage( + int page, { + required Duration duration, + required Curve curve, + }) async { _warpUnderwayCount += 1; - await _pageController! - .animateToPage(page, duration: duration, curve: curve); + await _pageController!.animateToPage( + page, + duration: duration, + curve: curve, + ); _warpUnderwayCount -= 1; } @@ -225,8 +231,11 @@ class _CustomTabBarViewState extends State { if (duration == Duration.zero) { _jumpToPage(_currentIndex!); } else { - await _animateToPage(_currentIndex!, - duration: duration, curve: Curves.ease); + await _animateToPage( + _currentIndex!, + duration: duration, + curve: Curves.ease, + ); } if (mounted) { setState(() { @@ -263,8 +272,11 @@ class _CustomTabBarViewState extends State { if (duration == Duration.zero) { _jumpToPage(_currentIndex!); } else { - await _animateToPage(_currentIndex!, - duration: duration, curve: Curves.ease); + await _animateToPage( + _currentIndex!, + duration: duration, + curve: Curves.ease, + ); } if (mounted) { @@ -275,8 +287,11 @@ class _CustomTabBarViewState extends State { } void _syncControllerOffset() { - _controller!.offset = - clampDouble(_pageController!.page! - _controller!.index, -1.0, 1.0); + _controller!.offset = clampDouble( + _pageController!.page! - _controller!.index, + -1.0, + 1.0, + ); } // Called when the PageView scrolls diff --git a/lib/common/widgets/text/paragraph.dart b/lib/common/widgets/text/paragraph.dart index 4cd1562d8..442a51ea7 100644 --- a/lib/common/widgets/text/paragraph.dart +++ b/lib/common/widgets/text/paragraph.dart @@ -11,7 +11,8 @@ library; import 'dart:collection'; import 'dart:math' as math; -import 'dart:ui' as ui +import 'dart:ui' + as ui show BoxHeightStyle, BoxWidthStyle, @@ -30,18 +31,18 @@ import 'package:flutter/services.dart'; /// The start and end positions for a text boundary. typedef _TextBoundaryRecord = ({ TextPosition boundaryStart, - TextPosition boundaryEnd + TextPosition boundaryEnd, }); /// Signature for a function that determines the [_TextBoundaryRecord] at the given /// [TextPosition]. -typedef _TextBoundaryAtPosition = _TextBoundaryRecord Function( - TextPosition position); +typedef _TextBoundaryAtPosition = + _TextBoundaryRecord Function(TextPosition position); /// Signature for a function that determines the [_TextBoundaryRecord] at the given /// [TextPosition], for the given [String]. -typedef _TextBoundaryAtPositionInText = _TextBoundaryRecord Function( - TextPosition position, String text); +typedef _TextBoundaryAtPositionInText = + _TextBoundaryRecord Function(TextPosition position, String text); const String _kEllipsis = '\u2026'; @@ -77,33 +78,35 @@ class RenderParagraph extends RenderBox Color? selectionColor, SelectionRegistrar? registrar, required Color primary, - }) : assert(text.debugAssertIsValid()), - assert(maxLines == null || - (maxLines > 0 && - overflow != TextOverflow.ellipsis && - overflow != TextOverflow.fade)), - assert( - identical(textScaler, TextScaler.noScaling) || textScaleFactor == 1.0, - 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', - ), - _primary = primary, - _softWrap = softWrap, - _overflow = overflow, - _selectionColor = selectionColor, - _textPainter = TextPainter( - text: text, - textAlign: textAlign, - textDirection: textDirection, - textScaler: textScaler == TextScaler.noScaling - ? TextScaler.linear(textScaleFactor) - : textScaler, - maxLines: maxLines, - ellipsis: overflow == TextOverflow.ellipsis ? _kEllipsis : null, - locale: locale, - strutStyle: strutStyle, - textWidthBasis: textWidthBasis, - textHeightBehavior: textHeightBehavior, - ) { + }) : assert(text.debugAssertIsValid()), + assert( + maxLines == null || + (maxLines > 0 && + overflow != TextOverflow.ellipsis && + overflow != TextOverflow.fade), + ), + assert( + identical(textScaler, TextScaler.noScaling) || textScaleFactor == 1.0, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ), + _primary = primary, + _softWrap = softWrap, + _overflow = overflow, + _selectionColor = selectionColor, + _textPainter = TextPainter( + text: text, + textAlign: textAlign, + textDirection: textDirection, + textScaler: textScaler == TextScaler.noScaling + ? TextScaler.linear(textScaleFactor) + : textScaler, + maxLines: maxLines, + ellipsis: overflow == TextOverflow.ellipsis ? _kEllipsis : null, + locale: locale, + strutStyle: strutStyle, + textWidthBasis: textWidthBasis, + textHeightBehavior: textHeightBehavior, + ) { addAll(children); this.registrar = registrar; } @@ -487,11 +490,11 @@ class RenderParagraph extends RenderBox double computeMinIntrinsicWidth(double height) { final List placeholderDimensions = layoutInlineChildren( - double.infinity, - (RenderBox child, BoxConstraints constraints) => - Size(child.getMinIntrinsicWidth(double.infinity), 0.0), - ChildLayoutHelper.getDryBaseline, - ); + double.infinity, + (RenderBox child, BoxConstraints constraints) => + Size(child.getMinIntrinsicWidth(double.infinity), 0.0), + ChildLayoutHelper.getDryBaseline, + ); return (_textIntrinsics ..setPlaceholderDimensions(placeholderDimensions) ..layout()) @@ -500,8 +503,8 @@ class RenderParagraph extends RenderBox @override double computeMaxIntrinsicWidth(double height) { - final List placeholderDimensions = - layoutInlineChildren( + final List + placeholderDimensions = layoutInlineChildren( double.infinity, // Height and baseline is irrelevant as all text will be laid // out in a single line. Therefore, using 0.0 as a dummy for the height. @@ -558,10 +561,10 @@ class RenderParagraph extends RenderBox // graphemeClusterLayoutBounds rects. final InlineSpan? spanHit = glyph != null && glyph.graphemeClusterLayoutBounds.contains(position) - ? _textPainter.text!.getSpanForPosition( - TextPosition(offset: glyph.graphemeClusterCodeUnitRange.start), - ) - : null; + ? _textPainter.text!.getSpanForPosition( + TextPosition(offset: glyph.graphemeClusterCodeUnitRange.start), + ) + : null; switch (spanHit) { case final HitTestTarget span: result.add(HitTestEntry(span)); @@ -604,26 +607,28 @@ class RenderParagraph extends RenderBox _textPainter ..setPlaceholderDimensions(_placeholderDimensions) ..layout( - minWidth: constraints.minWidth, - maxWidth: _adjustMaxWidth(constraints.maxWidth)); + minWidth: constraints.minWidth, + maxWidth: _adjustMaxWidth(constraints.maxWidth), + ); } @override @protected Size computeDryLayout(covariant BoxConstraints constraints) { - final Size size = (_textIntrinsics - ..setPlaceholderDimensions( - layoutInlineChildren( - constraints.maxWidth, - ChildLayoutHelper.dryLayoutChild, - ChildLayoutHelper.getDryBaseline, - ), - ) - ..layout( - minWidth: constraints.minWidth, - maxWidth: _adjustMaxWidth(constraints.maxWidth), - )) - .size; + final Size size = + (_textIntrinsics + ..setPlaceholderDimensions( + layoutInlineChildren( + constraints.maxWidth, + ChildLayoutHelper.dryLayoutChild, + ChildLayoutHelper.getDryBaseline, + ), + ) + ..layout( + minWidth: constraints.minWidth, + maxWidth: _adjustMaxWidth(constraints.maxWidth), + )) + .size; return constraints.constrain(size); } @@ -638,13 +643,16 @@ class RenderParagraph extends RenderBox // layouts. We should eventually change this back to pass the `baseline` // property when the ideographic baseline is properly implemented // (https://github.com/flutter/flutter/issues/22625). - return _textPainter - .computeDistanceToActualBaseline(TextBaseline.alphabetic); + return _textPainter.computeDistanceToActualBaseline( + TextBaseline.alphabetic, + ); } @override double computeDryBaseline( - covariant BoxConstraints constraints, TextBaseline baseline) { + covariant BoxConstraints constraints, + TextBaseline baseline, + ) { assert(constraints.debugAssertIsValid()); _textIntrinsics ..setPlaceholderDimensions( @@ -655,10 +663,12 @@ class RenderParagraph extends RenderBox ), ) ..layout( - minWidth: constraints.minWidth, - maxWidth: _adjustMaxWidth(constraints.maxWidth)); - return _textIntrinsics - .computeDistanceToActualBaseline(TextBaseline.alphabetic); + minWidth: constraints.minWidth, + maxWidth: _adjustMaxWidth(constraints.maxWidth), + ); + return _textIntrinsics.computeDistanceToActualBaseline( + TextBaseline.alphabetic, + ); } Color _primary; @@ -671,9 +681,9 @@ class RenderParagraph extends RenderBox } TextSpan get _moreTextSpan => TextSpan( - style: text.style!.copyWith(color: _primary), - text: '查看更多', - ); + style: text.style!.copyWith(color: _primary), + text: '查看更多', + ); TextPainter? _morePainter; bool didOverflowHeight = false; @@ -739,9 +749,9 @@ class RenderParagraph extends RenderBox final (double fadeStart, double fadeEnd) = switch (textDirection) { TextDirection.rtl => (fadeSizePainter.width, 0.0), TextDirection.ltr => ( - size.width - fadeSizePainter.width, - size.width - ), + size.width - fadeSizePainter.width, + size.width, + ), }; _overflowShader = ui.Gradient.linear( Offset(fadeStart, 0.0), @@ -915,11 +925,17 @@ class RenderParagraph extends RenderBox } TextPosition _getTextPositionVertical( - TextPosition position, double verticalOffset) { - final Offset caretOffset = - _textPainter.getOffsetForCaret(position, Rect.zero); - final Offset caretOffsetTranslated = - caretOffset.translate(0.0, verticalOffset); + TextPosition position, + double verticalOffset, + ) { + final Offset caretOffset = _textPainter.getOffsetForCaret( + position, + Rect.zero, + ); + final Offset caretOffsetTranslated = caretOffset.translate( + 0.0, + verticalOffset, + ); return _textPainter.getPositionForOffset(caretOffsetTranslated); } @@ -1018,7 +1034,9 @@ class RenderParagraph extends RenderBox if (seenTextInfo != null) { builder.markAsMergeUp( _createSemanticsConfigForTextInfo( - seenTextInfo, attributedLabelCacheIndex), + seenTextInfo, + attributedLabelCacheIndex, + ), ); attributedLabelCacheIndex += 1; } @@ -1040,7 +1058,9 @@ class RenderParagraph extends RenderBox if (seenTextInfo != null) { builder.markAsMergeUp( _createSemanticsConfigForTextInfo( - seenTextInfo, attributedLabelCacheIndex), + seenTextInfo, + attributedLabelCacheIndex, + ), ); } return builder.build(); @@ -1051,8 +1071,8 @@ class RenderParagraph extends RenderBox int cacheIndex, ) { assert(!textInfo.requiresOwnNode); - final List cachedStrings = - _cachedAttributedLabels ??= []; + final List cachedStrings = _cachedAttributedLabels ??= + []; assert(cacheIndex <= cachedStrings.length); final bool hasCache = cacheIndex < cachedStrings.length; @@ -1161,15 +1181,15 @@ class RenderParagraph extends RenderBox switch (info.recognizer) { case TapGestureRecognizer(onTap: final VoidCallback? handler): case DoubleTapGestureRecognizer( - onDoubleTap: final VoidCallback? handler - ): + onDoubleTap: final VoidCallback? handler, + ): if (handler != null) { configuration.onTap = handler; configuration.isLink = true; } case LongPressGestureRecognizer( - onLongPress: final GestureLongPressCallback? onLongPress - ): + onLongPress: final GestureLongPressCallback? onLongPress, + ): if (onLongPress != null) { configuration.onLongPress = onLongPress; } @@ -1179,8 +1199,9 @@ class RenderParagraph extends RenderBox assert(false, '${info.recognizer.runtimeType} is not supported.'); } if (node.parentPaintClipRect != null) { - final Rect paintRect = - node.parentPaintClipRect!.intersect(currentRect); + final Rect paintRect = node.parentPaintClipRect!.intersect( + currentRect, + ); configuration.isHidden = paintRect.isEmpty && !currentRect.isEmpty; } final SemanticsNode newChild; @@ -1189,7 +1210,9 @@ class RenderParagraph extends RenderBox } else { final UniqueKey key = UniqueKey(); newChild = SemanticsNode( - key: key, showOnScreen: _createShowOnScreenFor(key)); + key: key, + showOnScreen: _createShowOnScreenFor(key), + ); } newChild ..updateWith(config: configuration) @@ -1223,7 +1246,9 @@ class RenderParagraph extends RenderBox List debugDescribeChildren() { return [ text.toDiagnosticsNode( - name: 'text', style: DiagnosticsTreeStyle.transition), + name: 'text', + style: DiagnosticsTreeStyle.transition, + ), ]; } @@ -1243,11 +1268,15 @@ class RenderParagraph extends RenderBox ); properties.add(EnumProperty('overflow', overflow)); properties.add( - DiagnosticsProperty('textScaler', textScaler, - defaultValue: TextScaler.noScaling), + DiagnosticsProperty( + 'textScaler', + textScaler, + defaultValue: TextScaler.noScaling, + ), + ); + properties.add( + DiagnosticsProperty('locale', locale, defaultValue: null), ); - properties - .add(DiagnosticsProperty('locale', locale, defaultValue: null)); properties.add(IntProperty('maxLines', maxLines, ifNull: 'unlimited')); } } @@ -1262,9 +1291,11 @@ class RenderParagraph extends RenderBox class _SelectableFragment with Selectable, Diagnosticable, ChangeNotifier implements TextLayoutMetrics { - _SelectableFragment( - {required this.paragraph, required this.fullText, required this.range}) - : assert(range.isValid && !range.isCollapsed && range.isNormalized) { + _SelectableFragment({ + required this.paragraph, + required this.fullText, + required this.range, + }) : assert(range.isValid && !range.isCollapsed && range.isNormalized) { if (kFlutterMemoryAllocationsEnabled) { ChangeNotifier.maybeDispatchObjectCreation(this); } @@ -1299,18 +1330,20 @@ class _SelectableFragment SelectionGeometry _getSelectionGeometry() { if (_textSelectionStart == null || _textSelectionEnd == null) { return const SelectionGeometry( - status: SelectionStatus.none, hasContent: true); + status: SelectionStatus.none, + hasContent: true, + ); } final int selectionStart = _textSelectionStart!.offset; final int selectionEnd = _textSelectionEnd!.offset; final bool isReversed = selectionStart > selectionEnd; - final Offset startOffsetInParagraphCoordinates = - paragraph._getOffsetForPosition( - TextPosition(offset: selectionStart), - ); - final Offset endOffsetInParagraphCoordinates = selectionStart == - selectionEnd + final Offset startOffsetInParagraphCoordinates = paragraph + ._getOffsetForPosition( + TextPosition(offset: selectionStart), + ); + final Offset endOffsetInParagraphCoordinates = + selectionStart == selectionEnd ? startOffsetInParagraphCoordinates : paragraph._getOffsetForPosition(TextPosition(offset: selectionEnd)); final bool flipHandles = @@ -1330,17 +1363,17 @@ class _SelectableFragment ) = switch ((selectionCollapsed, flipHandles)) { // Always prefer collapsed handle when selection is collapsed. (true, _) => ( - TextSelectionHandleType.collapsed, - TextSelectionHandleType.collapsed - ), + TextSelectionHandleType.collapsed, + TextSelectionHandleType.collapsed, + ), (false, true) => ( - TextSelectionHandleType.right, - TextSelectionHandleType.left - ), + TextSelectionHandleType.right, + TextSelectionHandleType.left, + ), (false, false) => ( - TextSelectionHandleType.left, - TextSelectionHandleType.right - ), + TextSelectionHandleType.left, + TextSelectionHandleType.right, + ), }; return SelectionGeometry( startSelectionPoint: SelectionPoint( @@ -1394,8 +1427,10 @@ class _SelectableFragment ); case TextGranularity.document: case TextGranularity.line: - assert(false, - 'Moving the selection edge by line or document is not supported.'); + assert( + false, + 'Moving the selection edge by line or document is not supported.', + ); } case SelectionEventType.clear: result = _handleClearSelection(); @@ -1445,10 +1480,14 @@ class _SelectableFragment if (_textSelectionStart == null || _textSelectionEnd == null) { return null; } - final int start = - math.min(_textSelectionStart!.offset, _textSelectionEnd!.offset); - final int end = - math.max(_textSelectionStart!.offset, _textSelectionEnd!.offset); + final int start = math.min( + _textSelectionStart!.offset, + _textSelectionEnd!.offset, + ); + final int end = math.max( + _textSelectionStart!.offset, + _textSelectionEnd!.offset, + ); return SelectedContent(plainText: fullText.substring(start, end)); } @@ -1488,7 +1527,8 @@ class _SelectableFragment position.offset == existingSelectionEnd.offset; final bool isSelectionInverted = existingSelectionStart.offset > existingSelectionEnd.offset; - final bool shouldSwapEdges = !isSamePosition && + final bool shouldSwapEdges = + !isSamePosition && (isSelectionInverted != (position.offset > existingSelectionEnd.offset)); if (shouldSwapEdges) { @@ -1500,8 +1540,9 @@ class _SelectableFragment // When the selection is inverted by the new position it is necessary to // swap the start edge (moving edge) with the end edge (static edge) to // maintain the origin text boundary within the selection. - final _TextBoundaryRecord localTextBoundary = - getTextBoundary(existingSelectionEnd); + final _TextBoundaryRecord localTextBoundary = getTextBoundary( + existingSelectionEnd, + ); assert( localTextBoundary.boundaryStart.offset >= range.start && localTextBoundary.boundaryEnd.offset <= range.end, @@ -1551,13 +1592,15 @@ class _SelectableFragment position.offset == existingSelectionEnd.offset; final bool isSelectionInverted = existingSelectionStart.offset > existingSelectionEnd.offset; - final bool shouldSwapEdges = !isSamePosition && + final bool shouldSwapEdges = + !isSamePosition && (isSelectionInverted != (position.offset > existingSelectionEnd.offset)); if (shouldSwapEdges) { - final _TextBoundaryRecord localTextBoundary = - getTextBoundary(existingSelectionEnd); + final _TextBoundaryRecord localTextBoundary = getTextBoundary( + existingSelectionEnd, + ); assert( localTextBoundary.boundaryStart.offset >= range.start && localTextBoundary.boundaryEnd.offset <= range.end, @@ -1594,7 +1637,8 @@ class _SelectableFragment position.offset == existingSelectionStart.offset; final bool isSelectionInverted = existingSelectionStart.offset > existingSelectionEnd.offset; - final bool shouldSwapEdges = !isSamePosition && + final bool shouldSwapEdges = + !isSamePosition && (isSelectionInverted != (position.offset < existingSelectionStart.offset)); if (shouldSwapEdges) { @@ -1606,8 +1650,9 @@ class _SelectableFragment // When the selection is inverted by the new position it is necessary to // swap the end edge (moving edge) with the start edge (static edge) to // maintain the origin text boundary within the selection. - final _TextBoundaryRecord localTextBoundary = - getTextBoundary(existingSelectionStart); + final _TextBoundaryRecord localTextBoundary = getTextBoundary( + existingSelectionStart, + ); assert( localTextBoundary.boundaryStart.offset >= range.start && localTextBoundary.boundaryEnd.offset <= range.end, @@ -1657,12 +1702,14 @@ class _SelectableFragment position.offset == existingSelectionStart.offset; final bool isSelectionInverted = existingSelectionStart.offset > existingSelectionEnd.offset; - final bool shouldSwapEdges = isSelectionInverted != + final bool shouldSwapEdges = + isSelectionInverted != (position.offset < existingSelectionStart.offset) || isSamePosition; if (shouldSwapEdges) { - final _TextBoundaryRecord localTextBoundary = - getTextBoundary(existingSelectionStart); + final _TextBoundaryRecord localTextBoundary = getTextBoundary( + existingSelectionStart, + ); assert( localTextBoundary.boundaryStart.offset >= range.start && localTextBoundary.boundaryEnd.offset <= range.end, @@ -1693,8 +1740,10 @@ class _SelectableFragment _setSelectionPosition(null, isEnd: isEnd); final Matrix4 transform = paragraph.getTransformTo(null); transform.invert(); - final Offset localPosition = - MatrixUtils.transformPoint(transform, globalPosition); + final Offset localPosition = MatrixUtils.transformPoint( + transform, + globalPosition, + ); if (_rect.isEmpty) { return SelectionUtils.getResultBasedOnRect(_rect, localPosition); } @@ -1704,14 +1753,16 @@ class _SelectableFragment direction: paragraph.textDirection, ); - final TextPosition position = - paragraph.getPositionForOffset(adjustedOffset); + final TextPosition position = paragraph.getPositionForOffset( + adjustedOffset, + ); // Check if the original local position is within the rect, if it is not then // we do not need to look up the text boundary for that position. This is to // maintain a selectables selection collapsed at 0 when the local position is // not located inside its rect. - _TextBoundaryRecord? textBoundary = - _rect.contains(localPosition) ? getTextBoundary(position) : null; + _TextBoundaryRecord? textBoundary = _rect.contains(localPosition) + ? getTextBoundary(position) + : null; if (textBoundary != null && (textBoundary.boundaryStart.offset < range.start && textBoundary.boundaryEnd.offset <= range.start || @@ -1756,13 +1807,17 @@ class _SelectableFragment return SelectionUtils.getResultBasedOnRect(_rect, localPosition); } - SelectionResult _updateSelectionEdge(Offset globalPosition, - {required bool isEnd}) { + SelectionResult _updateSelectionEdge( + Offset globalPosition, { + required bool isEnd, + }) { _setSelectionPosition(null, isEnd: isEnd); final Matrix4 transform = paragraph.getTransformTo(null); transform.invert(); - final Offset localPosition = - MatrixUtils.transformPoint(transform, globalPosition); + final Offset localPosition = MatrixUtils.transformPoint( + transform, + globalPosition, + ); if (_rect.isEmpty) { return SelectionUtils.getResultBasedOnRect(_rect, localPosition); } @@ -1818,8 +1873,10 @@ class _SelectableFragment if (paragraphContainsPosition) { // When the position is within the root paragraph, swap the start and end // edges when the selection is inverted. - final _TextBoundaryRecord boundaryAtPosition = - getTextBoundary(position, fullText); + final _TextBoundaryRecord boundaryAtPosition = getTextBoundary( + position, + fullText, + ); // To accurately retrieve the origin text boundary when the selection // is forward, use existingSelectionEnd.offset - 1. This is necessary // because in a forwards selection, existingSelectionEnd marks the end @@ -1846,8 +1903,9 @@ class _SelectableFragment targetPosition = boundaryAtPosition.boundaryEnd; } else { // Keep the origin text boundary in bounds when position is at the static edge. - targetPosition = - forwardSelection ? existingSelectionStart : existingSelectionEnd; + targetPosition = forwardSelection + ? existingSelectionStart + : existingSelectionEnd; } if (shouldSwapEdges) { _setSelectionPosition( @@ -1917,15 +1975,17 @@ class _SelectableFragment } if (forwardSelection && clampedPosition.offset == range.end) { _setSelectionPosition( - _clampTextPosition(originTextBoundary.boundaryStart), - isEnd: true); + _clampTextPosition(originTextBoundary.boundaryStart), + isEnd: true, + ); _setSelectionPosition(clampedPosition, isEnd: isEnd); return SelectionResult.next; } if (!forwardSelection && clampedPosition.offset == range.start) { _setSelectionPosition( - _clampTextPosition(originTextBoundary.boundaryEnd), - isEnd: true); + _clampTextPosition(originTextBoundary.boundaryEnd), + isEnd: true, + ); _setSelectionPosition(clampedPosition, isEnd: isEnd); return SelectionResult.previous; } @@ -1937,14 +1997,17 @@ class _SelectableFragment // to allow traversal to reach that placeholder. final bool positionOnPlaceholder = paragraph.getWordBoundary(position).textInside(fullText) == - _placeholderCharacter; + _placeholderCharacter; if (!paragraphContainsPosition || positionOnPlaceholder) { return null; } if (existingSelectionEnd != null) { - final _TextBoundaryRecord boundaryAtPosition = - getTextBoundary(position, fullText); - final bool backwardSelection = existingSelectionStart == null && + final _TextBoundaryRecord boundaryAtPosition = getTextBoundary( + position, + fullText, + ); + final bool backwardSelection = + existingSelectionStart == null && existingSelectionEnd.offset == range.start || existingSelectionStart == existingSelectionEnd && existingSelectionEnd.offset == range.start || @@ -1952,8 +2015,10 @@ class _SelectableFragment existingSelectionStart.offset > existingSelectionEnd.offset; if (boundaryAtPosition.boundaryStart.offset < range.start && boundaryAtPosition.boundaryEnd.offset < range.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } if (boundaryAtPosition.boundaryStart.offset > range.end && @@ -1964,19 +2029,23 @@ class _SelectableFragment if (backwardSelection) { if (boundaryAtPosition.boundaryEnd.offset <= range.end) { _setSelectionPosition( - _clampTextPosition(boundaryAtPosition.boundaryEnd), - isEnd: isEnd); + _clampTextPosition(boundaryAtPosition.boundaryEnd), + isEnd: isEnd, + ); return SelectionResult.end; } if (boundaryAtPosition.boundaryEnd.offset > range.end) { - _setSelectionPosition(TextPosition(offset: range.end), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.end), + isEnd: isEnd, + ); return SelectionResult.next; } } else { _setSelectionPosition( - _clampTextPosition(boundaryAtPosition.boundaryStart), - isEnd: isEnd); + _clampTextPosition(boundaryAtPosition.boundaryStart), + isEnd: isEnd, + ); if (boundaryAtPosition.boundaryStart.offset < range.start) { return SelectionResult.previous; } @@ -2018,8 +2087,10 @@ class _SelectableFragment if (paragraphContainsPosition) { // When the position is within the root paragraph, swap the start and end // edges when the selection is inverted. - final _TextBoundaryRecord boundaryAtPosition = - getTextBoundary(position, fullText); + final _TextBoundaryRecord boundaryAtPosition = getTextBoundary( + position, + fullText, + ); // To accurately retrieve the origin text boundary when the selection // is backwards, use existingSelectionStart.offset - 1. This is necessary // because in a backwards selection, existingSelectionStart marks the end @@ -2046,8 +2117,9 @@ class _SelectableFragment targetPosition = boundaryAtPosition.boundaryEnd; } else { // Keep the origin text boundary in bounds when position is at the static edge. - targetPosition = - forwardSelection ? existingSelectionEnd : existingSelectionStart; + targetPosition = forwardSelection + ? existingSelectionEnd + : existingSelectionStart; } if (shouldSwapEdges) { _setSelectionPosition( @@ -2109,15 +2181,17 @@ class _SelectableFragment ); if (forwardSelection && clampedPosition.offset == range.start) { _setSelectionPosition( - _clampTextPosition(originTextBoundary.boundaryEnd), - isEnd: false); + _clampTextPosition(originTextBoundary.boundaryEnd), + isEnd: false, + ); _setSelectionPosition(clampedPosition, isEnd: isEnd); return SelectionResult.previous; } if (!forwardSelection && clampedPosition.offset == range.end) { _setSelectionPosition( - _clampTextPosition(originTextBoundary.boundaryStart), - isEnd: false); + _clampTextPosition(originTextBoundary.boundaryStart), + isEnd: false, + ); _setSelectionPosition(clampedPosition, isEnd: isEnd); return SelectionResult.next; } @@ -2137,14 +2211,17 @@ class _SelectableFragment // to allow traversal to reach that placeholder. final bool positionOnPlaceholder = paragraph.getWordBoundary(position).textInside(fullText) == - _placeholderCharacter; + _placeholderCharacter; if (!paragraphContainsPosition || positionOnPlaceholder) { return null; } if (existingSelectionStart != null) { - final _TextBoundaryRecord boundaryAtPosition = - getTextBoundary(position, fullText); - final bool backwardSelection = existingSelectionEnd == null && + final _TextBoundaryRecord boundaryAtPosition = getTextBoundary( + position, + fullText, + ); + final bool backwardSelection = + existingSelectionEnd == null && existingSelectionStart.offset == range.end || existingSelectionStart == existingSelectionEnd && existingSelectionStart.offset == range.end || @@ -2152,8 +2229,10 @@ class _SelectableFragment existingSelectionStart.offset > existingSelectionEnd.offset; if (boundaryAtPosition.boundaryStart.offset < range.start && boundaryAtPosition.boundaryEnd.offset < range.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } if (boundaryAtPosition.boundaryStart.offset > range.end && @@ -2163,8 +2242,9 @@ class _SelectableFragment } if (backwardSelection) { _setSelectionPosition( - _clampTextPosition(boundaryAtPosition.boundaryStart), - isEnd: isEnd); + _clampTextPosition(boundaryAtPosition.boundaryStart), + isEnd: isEnd, + ); if (boundaryAtPosition.boundaryStart.offset < range.start) { return SelectionResult.previous; } @@ -2174,13 +2254,16 @@ class _SelectableFragment } else { if (boundaryAtPosition.boundaryEnd.offset <= range.end) { _setSelectionPosition( - _clampTextPosition(boundaryAtPosition.boundaryEnd), - isEnd: isEnd); + _clampTextPosition(boundaryAtPosition.boundaryEnd), + isEnd: isEnd, + ); return SelectionResult.end; } if (boundaryAtPosition.boundaryEnd.offset > range.end) { - _setSelectionPosition(TextPosition(offset: range.end), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.end), + isEnd: isEnd, + ); return SelectionResult.next; } } @@ -2207,7 +2290,7 @@ class _SelectableFragment // See [_updateSelectionEndEdgeAtPlaceholderByMultiSelectableTextBoundary] for the method // that handles updating the end edge. SelectionResult? - _updateSelectionStartEdgeAtPlaceholderByMultiSelectableTextBoundary( + _updateSelectionStartEdgeAtPlaceholderByMultiSelectableTextBoundary( _TextBoundaryAtPositionInText getTextBoundary, Offset globalPosition, bool paragraphContainsPosition, @@ -2241,20 +2324,21 @@ class _SelectableFragment originTransform, globalPosition, ); - final bool positionWithinOriginParagraph = - originParagraph.paintBounds.contains( - originParagraphLocalPosition, - ); - final TextPosition positionRelativeToOriginParagraph = - originParagraph.getPositionForOffset( - originParagraphLocalPosition, - ); + final bool positionWithinOriginParagraph = originParagraph.paintBounds + .contains( + originParagraphLocalPosition, + ); + final TextPosition positionRelativeToOriginParagraph = originParagraph + .getPositionForOffset( + originParagraphLocalPosition, + ); if (positionWithinOriginParagraph) { // When the selection is inverted by the new position it is necessary to // swap the start edge (moving edge) with the end edge (static edge) to // maintain the origin text boundary within the selection. - final String originText = - originParagraph.text.toPlainText(includeSemanticsLabels: false); + final String originText = originParagraph.text.toPlainText( + includeSemanticsLabels: false, + ); final _TextBoundaryRecord boundaryAtPosition = getTextBoundary( positionRelativeToOriginParagraph, originText, @@ -2267,7 +2351,8 @@ class _SelectableFragment final int pivotOffset = forwardSelection ? originTextBoundary.boundaryEnd.offset : originTextBoundary.boundaryStart.offset; - final bool shouldSwapEdges = !forwardSelection != + final bool shouldSwapEdges = + !forwardSelection != (positionRelativeToOriginParagraph.offset > pivotOffset); if (positionRelativeToOriginParagraph.offset < pivotOffset) { targetPosition = boundaryAtPosition.boundaryStart; @@ -2285,11 +2370,12 @@ class _SelectableFragment _textSelectionEnd!.offset >= _textSelectionStart!.offset; final TextPosition originParagraphPlaceholderTextPosition = _getPositionInParagraph( - originParagraph, - ); + originParagraph, + ); final TextRange originParagraphPlaceholderRange = TextRange( start: originParagraphPlaceholderTextPosition.offset, - end: originParagraphPlaceholderTextPosition.offset + + end: + originParagraphPlaceholderTextPosition.offset + _placeholderLength, ); if (boundaryAtPosition.boundaryStart.offset > @@ -2339,18 +2425,21 @@ class _SelectableFragment originParagraph.getPositionForOffset(adjustedOffset); final TextPosition originParagraphPlaceholderTextPosition = _getPositionInParagraph( - originParagraph, - ); + originParagraph, + ); final TextRange originParagraphPlaceholderRange = TextRange( start: originParagraphPlaceholderTextPosition.offset, - end: originParagraphPlaceholderTextPosition.offset + + end: + originParagraphPlaceholderTextPosition.offset + _placeholderLength, ); if (forwardSelection && adjustedPositionRelativeToOriginParagraph.offset <= originParagraphPlaceholderRange.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } if (!forwardSelection && @@ -2370,8 +2459,10 @@ class _SelectableFragment adjustedPositionRelativeToOriginParagraph.offset <= originParagraphPlaceholderRange.start) { _setSelectionPosition(existingSelectionStart, isEnd: true); - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } } @@ -2389,28 +2480,29 @@ class _SelectableFragment ); } if (existingSelectionEnd != null) { - final ({ - RenderParagraph paragraph, - Offset localPosition - })? targetDetails = _getParagraphContainingPosition(globalPosition); + final ({RenderParagraph paragraph, Offset localPosition})? + targetDetails = _getParagraphContainingPosition(globalPosition); if (targetDetails == null) { return null; } final RenderParagraph targetParagraph = targetDetails.paragraph; - final TextPosition positionRelativeToTargetParagraph = - targetParagraph.getPositionForOffset( - targetDetails.localPosition, + final TextPosition positionRelativeToTargetParagraph = targetParagraph + .getPositionForOffset( + targetDetails.localPosition, + ); + final String targetText = targetParagraph.text.toPlainText( + includeSemanticsLabels: false, ); - final String targetText = - targetParagraph.text.toPlainText(includeSemanticsLabels: false); - final bool positionOnPlaceholder = targetParagraph + final bool positionOnPlaceholder = + targetParagraph .getWordBoundary(positionRelativeToTargetParagraph) .textInside(targetText) == _placeholderCharacter; if (positionOnPlaceholder) { return null; } - final bool backwardSelection = existingSelectionStart == null && + final bool backwardSelection = + existingSelectionStart == null && existingSelectionEnd.offset == range.start || existingSelectionStart == existingSelectionEnd && existingSelectionEnd.offset == range.start || @@ -2418,24 +2510,27 @@ class _SelectableFragment existingSelectionStart.offset > existingSelectionEnd.offset; final _TextBoundaryRecord boundaryAtPositionRelativeToTargetParagraph = getTextBoundary( - positionRelativeToTargetParagraph, - targetText, - ); + positionRelativeToTargetParagraph, + targetText, + ); final TextPosition targetParagraphPlaceholderTextPosition = _getPositionInParagraph( - targetParagraph, - ); + targetParagraph, + ); final TextRange targetParagraphPlaceholderRange = TextRange( start: targetParagraphPlaceholderTextPosition.offset, - end: targetParagraphPlaceholderTextPosition.offset + + end: + targetParagraphPlaceholderTextPosition.offset + _placeholderLength, ); if (boundaryAtPositionRelativeToTargetParagraph.boundaryStart.offset < targetParagraphPlaceholderRange.start && boundaryAtPositionRelativeToTargetParagraph.boundaryEnd.offset < targetParagraphPlaceholderRange.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } if (boundaryAtPositionRelativeToTargetParagraph.boundaryStart.offset > @@ -2448,28 +2543,37 @@ class _SelectableFragment if (backwardSelection) { if (boundaryAtPositionRelativeToTargetParagraph.boundaryEnd.offset <= targetParagraphPlaceholderRange.end) { - _setSelectionPosition(TextPosition(offset: range.end), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.end), + isEnd: isEnd, + ); return SelectionResult.end; } if (boundaryAtPositionRelativeToTargetParagraph.boundaryEnd.offset > targetParagraphPlaceholderRange.end) { - _setSelectionPosition(TextPosition(offset: range.end), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.end), + isEnd: isEnd, + ); return SelectionResult.next; } } else { if (boundaryAtPositionRelativeToTargetParagraph - .boundaryStart.offset >= + .boundaryStart + .offset >= targetParagraphPlaceholderRange.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.end; } if (boundaryAtPositionRelativeToTargetParagraph.boundaryStart.offset < targetParagraphPlaceholderRange.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } } @@ -2491,7 +2595,7 @@ class _SelectableFragment // See [_updateSelectionStartEdgeAtPlaceholderByMultiSelectableTextBoundary] // for the method that handles updating the start edge. SelectionResult? - _updateSelectionEndEdgeAtPlaceholderByMultiSelectableTextBoundary( + _updateSelectionEndEdgeAtPlaceholderByMultiSelectableTextBoundary( _TextBoundaryAtPositionInText getTextBoundary, Offset globalPosition, bool paragraphContainsPosition, @@ -2525,20 +2629,21 @@ class _SelectableFragment originTransform, globalPosition, ); - final bool positionWithinOriginParagraph = - originParagraph.paintBounds.contains( - originParagraphLocalPosition, - ); - final TextPosition positionRelativeToOriginParagraph = - originParagraph.getPositionForOffset( - originParagraphLocalPosition, - ); + final bool positionWithinOriginParagraph = originParagraph.paintBounds + .contains( + originParagraphLocalPosition, + ); + final TextPosition positionRelativeToOriginParagraph = originParagraph + .getPositionForOffset( + originParagraphLocalPosition, + ); if (positionWithinOriginParagraph) { // When the selection is inverted by the new position it is necessary to // swap the end edge (moving edge) with the start edge (static edge) to // maintain the origin text boundary within the selection. - final String originText = - originParagraph.text.toPlainText(includeSemanticsLabels: false); + final String originText = originParagraph.text.toPlainText( + includeSemanticsLabels: false, + ); final _TextBoundaryRecord boundaryAtPosition = getTextBoundary( positionRelativeToOriginParagraph, originText, @@ -2551,7 +2656,8 @@ class _SelectableFragment final int pivotOffset = forwardSelection ? originTextBoundary.boundaryStart.offset : originTextBoundary.boundaryEnd.offset; - final bool shouldSwapEdges = !forwardSelection != + final bool shouldSwapEdges = + !forwardSelection != (positionRelativeToOriginParagraph.offset < pivotOffset); if (positionRelativeToOriginParagraph.offset < pivotOffset) { targetPosition = boundaryAtPosition.boundaryStart; @@ -2569,11 +2675,12 @@ class _SelectableFragment _textSelectionEnd!.offset >= _textSelectionStart!.offset; final TextPosition originParagraphPlaceholderTextPosition = _getPositionInParagraph( - originParagraph, - ); + originParagraph, + ); final TextRange originParagraphPlaceholderRange = TextRange( start: originParagraphPlaceholderTextPosition.offset, - end: originParagraphPlaceholderTextPosition.offset + + end: + originParagraphPlaceholderTextPosition.offset + _placeholderLength, ); if (boundaryAtPosition.boundaryStart.offset > @@ -2623,19 +2730,22 @@ class _SelectableFragment originParagraph.getPositionForOffset(adjustedOffset); final TextPosition originParagraphPlaceholderTextPosition = _getPositionInParagraph( - originParagraph, - ); + originParagraph, + ); final TextRange originParagraphPlaceholderRange = TextRange( start: originParagraphPlaceholderTextPosition.offset, - end: originParagraphPlaceholderTextPosition.offset + + end: + originParagraphPlaceholderTextPosition.offset + _placeholderLength, ); if (forwardSelection && adjustedPositionRelativeToOriginParagraph.offset <= originParagraphPlaceholderRange.start) { _setSelectionPosition(existingSelectionEnd, isEnd: false); - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } if (!forwardSelection && @@ -2654,8 +2764,10 @@ class _SelectableFragment if (!forwardSelection && adjustedPositionRelativeToOriginParagraph.offset <= originParagraphPlaceholderRange.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } } @@ -2673,28 +2785,29 @@ class _SelectableFragment ); } if (existingSelectionStart != null) { - final ({ - RenderParagraph paragraph, - Offset localPosition - })? targetDetails = _getParagraphContainingPosition(globalPosition); + final ({RenderParagraph paragraph, Offset localPosition})? + targetDetails = _getParagraphContainingPosition(globalPosition); if (targetDetails == null) { return null; } final RenderParagraph targetParagraph = targetDetails.paragraph; - final TextPosition positionRelativeToTargetParagraph = - targetParagraph.getPositionForOffset( - targetDetails.localPosition, + final TextPosition positionRelativeToTargetParagraph = targetParagraph + .getPositionForOffset( + targetDetails.localPosition, + ); + final String targetText = targetParagraph.text.toPlainText( + includeSemanticsLabels: false, ); - final String targetText = - targetParagraph.text.toPlainText(includeSemanticsLabels: false); - final bool positionOnPlaceholder = targetParagraph + final bool positionOnPlaceholder = + targetParagraph .getWordBoundary(positionRelativeToTargetParagraph) .textInside(targetText) == _placeholderCharacter; if (positionOnPlaceholder) { return null; } - final bool backwardSelection = existingSelectionEnd == null && + final bool backwardSelection = + existingSelectionEnd == null && existingSelectionStart.offset == range.end || existingSelectionStart == existingSelectionEnd && existingSelectionStart.offset == range.end || @@ -2702,24 +2815,27 @@ class _SelectableFragment existingSelectionStart.offset > existingSelectionEnd.offset; final _TextBoundaryRecord boundaryAtPositionRelativeToTargetParagraph = getTextBoundary( - positionRelativeToTargetParagraph, - targetText, - ); + positionRelativeToTargetParagraph, + targetText, + ); final TextPosition targetParagraphPlaceholderTextPosition = _getPositionInParagraph( - targetParagraph, - ); + targetParagraph, + ); final TextRange targetParagraphPlaceholderRange = TextRange( start: targetParagraphPlaceholderTextPosition.offset, - end: targetParagraphPlaceholderTextPosition.offset + + end: + targetParagraphPlaceholderTextPosition.offset + _placeholderLength, ); if (boundaryAtPositionRelativeToTargetParagraph.boundaryStart.offset < targetParagraphPlaceholderRange.start && boundaryAtPositionRelativeToTargetParagraph.boundaryEnd.offset < targetParagraphPlaceholderRange.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } if (boundaryAtPositionRelativeToTargetParagraph.boundaryStart.offset > @@ -2731,29 +2847,38 @@ class _SelectableFragment } if (backwardSelection) { if (boundaryAtPositionRelativeToTargetParagraph - .boundaryStart.offset >= + .boundaryStart + .offset >= targetParagraphPlaceholderRange.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.end; } if (boundaryAtPositionRelativeToTargetParagraph.boundaryStart.offset < targetParagraphPlaceholderRange.start) { - _setSelectionPosition(TextPosition(offset: range.start), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.start), + isEnd: isEnd, + ); return SelectionResult.previous; } } else { if (boundaryAtPositionRelativeToTargetParagraph.boundaryEnd.offset <= targetParagraphPlaceholderRange.end) { - _setSelectionPosition(TextPosition(offset: range.end), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.end), + isEnd: isEnd, + ); return SelectionResult.end; } if (boundaryAtPositionRelativeToTargetParagraph.boundaryEnd.offset > targetParagraphPlaceholderRange.end) { - _setSelectionPosition(TextPosition(offset: range.end), - isEnd: isEnd); + _setSelectionPosition( + TextPosition(offset: range.end), + isEnd: isEnd, + ); return SelectionResult.next; } } @@ -2777,8 +2902,10 @@ class _SelectableFragment _setSelectionPosition(null, isEnd: isEnd); final Matrix4 transform = paragraph.getTransformTo(null); transform.invert(); - final Offset localPosition = - MatrixUtils.transformPoint(transform, globalPosition); + final Offset localPosition = MatrixUtils.transformPoint( + transform, + globalPosition, + ); if (_rect.isEmpty) { return SelectionUtils.getResultBasedOnRect(_rect, localPosition); } @@ -2789,13 +2916,14 @@ class _SelectableFragment ); final Offset adjustedOffsetRelativeToParagraph = SelectionUtils.adjustDragOffset( - paragraph.paintBounds, - localPosition, - direction: paragraph.textDirection, - ); + paragraph.paintBounds, + localPosition, + direction: paragraph.textDirection, + ); - final TextPosition position = - paragraph.getPositionForOffset(adjustedOffset); + final TextPosition position = paragraph.getPositionForOffset( + adjustedOffset, + ); final TextPosition positionInFullText = paragraph.getPositionForOffset( adjustedOffsetRelativeToParagraph, ); @@ -2892,11 +3020,13 @@ class _SelectableFragment } TextPosition _closestTextBoundary( - _TextBoundaryRecord textBoundary, TextPosition position) { + _TextBoundaryRecord textBoundary, + TextPosition position, + ) { final int differenceA = (position.offset - textBoundary.boundaryStart.offset).abs(); - final int differenceB = - (position.offset - textBoundary.boundaryEnd.offset).abs(); + final int differenceB = (position.offset - textBoundary.boundaryEnd.offset) + .abs(); return differenceA < differenceB ? textBoundary.boundaryStart : textBoundary.boundaryEnd; @@ -2946,7 +3076,7 @@ class _SelectableFragment } ({RenderParagraph paragraph, Offset localPosition})? - _getParagraphContainingPosition( + _getParagraphContainingPosition( Offset globalPosition, ) { // This method will return the closest [RenderParagraph] whose rect @@ -2962,14 +3092,14 @@ class _SelectableFragment currentTransform, globalPosition, ); - final bool positionWithinCurrentParagraph = - current.paintBounds.contains( - currentParagraphLocalPosition, - ); + final bool positionWithinCurrentParagraph = current.paintBounds + .contains( + currentParagraphLocalPosition, + ); if (positionWithinCurrentParagraph) { return ( paragraph: current, - localPosition: currentParagraphLocalPosition + localPosition: currentParagraphLocalPosition, ); } } @@ -3017,8 +3147,10 @@ class _SelectableFragment SelectionResult _handleSelectAll() { _textSelectionStart = TextPosition(offset: range.start); - _textSelectionEnd = - TextPosition(offset: range.end, affinity: TextAffinity.upstream); + _textSelectionEnd = TextPosition( + offset: range.end, + affinity: TextAffinity.upstream, + ); return SelectionResult.none; } @@ -3059,7 +3191,8 @@ class _SelectableFragment } SelectionResult _handleSelectMultiFragmentTextBoundary( - _TextBoundaryRecord textBoundary) { + _TextBoundaryRecord textBoundary, + ) { // This fragment may not contain the boundary, decide what direction the target // fragment is located in. Because fragments are separated by placeholder // spans, we also check if the beginning or end of the boundary is touching @@ -3089,7 +3222,9 @@ class _SelectableFragment } _TextBoundaryRecord _adjustTextBoundaryAtPosition( - TextRange textBoundary, TextPosition position) { + TextRange textBoundary, + TextPosition position, + ) { late final TextPosition start; late final TextPosition end; if (position.offset > textBoundary.end) { @@ -3097,7 +3232,9 @@ class _SelectableFragment } else { start = TextPosition(offset: textBoundary.start); end = TextPosition( - offset: textBoundary.end, affinity: TextAffinity.upstream); + offset: textBoundary.end, + affinity: TextAffinity.upstream, + ); } return (boundaryStart: start, boundaryEnd: end); } @@ -3110,8 +3247,9 @@ class _SelectableFragment _textSelectionStart != _textSelectionEnd) { return SelectionResult.end; } - final _TextBoundaryRecord wordBoundary = - _getWordBoundaryAtPosition(position); + final _TextBoundaryRecord wordBoundary = _getWordBoundaryAtPosition( + position, + ); return _handleSelectTextBoundary(wordBoundary); } @@ -3126,9 +3264,9 @@ class _SelectableFragment final TextPosition position = paragraph.getPositionForOffset(localPosition); final _TextBoundaryRecord paragraphBoundary = _getParagraphBoundaryAtPosition( - position, - fullText, - ); + position, + fullText, + ); return _handleSelectMultiFragmentTextBoundary(paragraphBoundary); } @@ -3136,17 +3274,21 @@ class _SelectableFragment final Matrix4 transform = paragraph.getTransformTo(targetParagraph); final Offset localCenter = paragraph.paintBounds.centerLeft; final Offset localPos = MatrixUtils.transformPoint(transform, localCenter); - final TextPosition position = - targetParagraph.getPositionForOffset(localPos); + final TextPosition position = targetParagraph.getPositionForOffset( + localPos, + ); return position; } _TextBoundaryRecord _getParagraphBoundaryAtPosition( - TextPosition position, String text) { + TextPosition position, + String text, + ) { final ParagraphBoundary paragraphBoundary = ParagraphBoundary(text); // Use position.offset - 1 when `position` is at the end of the selectable to retrieve // the previous text boundary's location. - final int paragraphStart = paragraphBoundary.getLeadingTextBoundaryAt( + final int paragraphStart = + paragraphBoundary.getLeadingTextBoundaryAt( position.offset == text.length || position.affinity == TextAffinity.upstream ? position.offset - 1 @@ -3155,19 +3297,23 @@ class _SelectableFragment 0; final int paragraphEnd = paragraphBoundary.getTrailingTextBoundaryAt(position.offset) ?? - text.length; - final TextRange paragraphRange = - TextRange(start: paragraphStart, end: paragraphEnd); + text.length; + final TextRange paragraphRange = TextRange( + start: paragraphStart, + end: paragraphEnd, + ); assert(paragraphRange.isNormalized); return _adjustTextBoundaryAtPosition(paragraphRange, position); } _TextBoundaryRecord _getClampedParagraphBoundaryAtPosition( - TextPosition position) { + TextPosition position, + ) { final ParagraphBoundary paragraphBoundary = ParagraphBoundary(fullText); // Use position.offset - 1 when `position` is at the end of the selectable to retrieve // the previous text boundary's location. - int paragraphStart = paragraphBoundary.getLeadingTextBoundaryAt( + int paragraphStart = + paragraphBoundary.getLeadingTextBoundaryAt( position.offset == fullText.length || position.affinity == TextAffinity.upstream ? position.offset - 1 @@ -3176,19 +3322,21 @@ class _SelectableFragment 0; int paragraphEnd = paragraphBoundary.getTrailingTextBoundaryAt(position.offset) ?? - fullText.length; + fullText.length; paragraphStart = paragraphStart < range.start ? range.start : paragraphStart > range.end - ? range.end - : paragraphStart; + ? range.end + : paragraphStart; paragraphEnd = paragraphEnd > range.end ? range.end : paragraphEnd < range.start - ? range.start - : paragraphEnd; - final TextRange paragraphRange = - TextRange(start: paragraphStart, end: paragraphEnd); + ? range.start + : paragraphEnd; + final TextRange paragraphRange = TextRange( + start: paragraphStart, + end: paragraphEnd, + ); assert(paragraphRange.isNormalized); return _adjustTextBoundaryAtPosition(paragraphRange, position); } @@ -3209,8 +3357,10 @@ class _SelectableFragment return SelectionResult.next; } } - final double baselineInParagraphCoordinates = - MatrixUtils.transformPoint(transform, Offset(horizontalBaseline, 0)).dx; + final double baselineInParagraphCoordinates = MatrixUtils.transformPoint( + transform, + Offset(horizontalBaseline, 0), + ).dx; assert(!baselineInParagraphCoordinates.isNaN); final TextPosition newPosition; final SelectionResult result; @@ -3218,15 +3368,16 @@ class _SelectableFragment case SelectionExtendDirection.previousLine: case SelectionExtendDirection.nextLine: assert(_textSelectionEnd != null && _textSelectionStart != null); - final TextPosition targetedEdge = - isExtent ? _textSelectionEnd! : _textSelectionStart!; + final TextPosition targetedEdge = isExtent + ? _textSelectionEnd! + : _textSelectionStart!; final MapEntry moveResult = _handleVerticalMovement( - targetedEdge, - horizontalBaselineInParagraphCoordinates: - baselineInParagraphCoordinates, - below: movement == SelectionExtendDirection.nextLine, - ); + targetedEdge, + horizontalBaselineInParagraphCoordinates: + baselineInParagraphCoordinates, + below: movement == SelectionExtendDirection.nextLine, + ); newPosition = moveResult.key; result = moveResult.value; case SelectionExtendDirection.forward: @@ -3235,20 +3386,22 @@ class _SelectableFragment ? TextPosition(offset: range.start) : TextPosition(offset: range.end, affinity: TextAffinity.upstream); _textSelectionStart ??= _textSelectionEnd; - final TextPosition targetedEdge = - isExtent ? _textSelectionEnd! : _textSelectionStart!; - final Offset edgeOffsetInParagraphCoordinates = - paragraph._getOffsetForPosition( - targetedEdge, - ); + final TextPosition targetedEdge = isExtent + ? _textSelectionEnd! + : _textSelectionStart!; + final Offset edgeOffsetInParagraphCoordinates = paragraph + ._getOffsetForPosition( + targetedEdge, + ); final Offset baselineOffsetInParagraphCoordinates = Offset( baselineInParagraphCoordinates, // Use half of line height to point to the middle of the line. edgeOffsetInParagraphCoordinates.dy - paragraph._textPainter.preferredLineHeight / 2, ); - newPosition = paragraph - .getPositionForOffset(baselineOffsetInParagraphCoordinates); + newPosition = paragraph.getPositionForOffset( + baselineOffsetInParagraphCoordinates, + ); result = SelectionResult.end; } if (isExtent) { @@ -3268,8 +3421,9 @@ class _SelectableFragment ? TextPosition(offset: range.start) : TextPosition(offset: range.end, affinity: TextAffinity.upstream); _textSelectionStart ??= _textSelectionEnd; - final TextPosition targetedEdge = - isExtent ? _textSelectionEnd! : _textSelectionStart!; + final TextPosition targetedEdge = isExtent + ? _textSelectionEnd! + : _textSelectionStart!; if (forward && (targetedEdge.offset == range.end)) { return SelectionResult.next; } @@ -3291,7 +3445,10 @@ class _SelectableFragment final TextBoundary textBoundary = paragraph._textPainter.wordBoundaries.moveByWordBoundary; newPosition = _moveBeyondTextBoundaryAtDirection( - targetedEdge, forward, textBoundary); + targetedEdge, + forward, + textBoundary, + ); result = SelectionResult.end; case TextGranularity.paragraph: final String text = range.textInside(fullText); @@ -3303,7 +3460,10 @@ class _SelectableFragment result = SelectionResult.end; case TextGranularity.line: newPosition = _moveToTextBoundaryAtDirection( - targetedEdge, forward, LineBoundary(this)); + targetedEdge, + forward, + LineBoundary(this), + ); result = SelectionResult.end; case TextGranularity.document: final String text = range.textInside(fullText); @@ -3361,10 +3521,12 @@ class _SelectableFragment return const TextPosition(offset: 0); } final CharacterBoundary characterBoundary = CharacterBoundary(fullText); - caretOffset = math.max( + caretOffset = + math.max( 0, - characterBoundary - .getLeadingTextBoundaryAt(range.start + end.offset) ?? + characterBoundary.getLeadingTextBoundaryAt( + range.start + end.offset, + ) ?? range.start, ) - 1; @@ -3382,8 +3544,8 @@ class _SelectableFragment required double horizontalBaselineInParagraphCoordinates, required bool below, }) { - final List lines = - paragraph._textPainter.computeLineMetrics(); + final List lines = paragraph._textPainter + .computeLineMetrics(); final Offset offset = paragraph.getOffsetForCaret(position, Rect.zero); int currentLine = lines.length - 1; for (final ui.LineMetrics lineMetrics in lines) { @@ -3394,16 +3556,20 @@ class _SelectableFragment } final TextPosition newPosition; if (below && currentLine == lines.length - 1) { - newPosition = - TextPosition(offset: range.end, affinity: TextAffinity.upstream); + newPosition = TextPosition( + offset: range.end, + affinity: TextAffinity.upstream, + ); } else if (!below && currentLine == 0) { newPosition = TextPosition(offset: range.start); } else { final int newLine = below ? currentLine + 1 : currentLine - 1; newPosition = _clampTextPosition( paragraph.getPositionForOffset( - Offset(horizontalBaselineInParagraphCoordinates, - lines[newLine].baseline), + Offset( + horizontalBaselineInParagraphCoordinates, + lines[newLine].baseline, + ), ), ); } @@ -3447,7 +3613,9 @@ class _SelectableFragment /// Returns 1 if `position` < `otherPosition`, -1 if `position` > `otherPosition`, /// or 0 if they are equal. static int _compareTextPositions( - TextPosition position, TextPosition otherPosition) { + TextPosition position, + TextPosition otherPosition, + ) { if (position.offset < otherPosition.offset) { return 1; } else if (position.offset > otherPosition.offset) { @@ -3467,8 +3635,10 @@ class _SelectableFragment @override void pushHandleLayers(LayerLink? startHandle, LayerLink? endHandle) { if (!paragraph.attached) { - assert(startHandle == null && endHandle == null, - 'Only clean up can be called.'); + assert( + startHandle == null && endHandle == null, + 'Only clean up can be called.', + ); return; } if (_startHandleLayerLink != startHandle) { @@ -3495,8 +3665,9 @@ class _SelectableFragment _cachedBoundingBoxes!.add(textBox.toRect()); } } else { - final Offset offset = - paragraph._getOffsetForPosition(TextPosition(offset: range.start)); + final Offset offset = paragraph._getOffsetForPosition( + TextPosition(offset: range.start), + ); final Rect rect = Rect.fromPoints( offset, offset.translate(0, -paragraph._textPainter.preferredLineHeight), @@ -3520,8 +3691,9 @@ class _SelectableFragment } _cachedRect = result; } else { - final Offset offset = - paragraph._getOffsetForPosition(TextPosition(offset: range.start)); + final Offset offset = paragraph._getOffsetForPosition( + TextPosition(offset: range.start), + ); _cachedRect = Rect.fromPoints( offset, offset.translate(0, -paragraph._textPainter.preferredLineHeight), @@ -3607,8 +3779,12 @@ class _SelectableFragment @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty( - 'textInsideRange', range.textInside(fullText))); + properties.add( + DiagnosticsProperty( + 'textInsideRange', + range.textInside(fullText), + ), + ); properties.add(DiagnosticsProperty('range', range)); properties.add(DiagnosticsProperty('fullText', fullText)); } diff --git a/lib/common/widgets/text/rich_text.dart b/lib/common/widgets/text/rich_text.dart index 0917f1f80..6d3b67f46 100644 --- a/lib/common/widgets/text/rich_text.dart +++ b/lib/common/widgets/text/rich_text.dart @@ -114,26 +114,29 @@ class RichText extends MultiChildRenderObjectWidget { this.textHeightBehavior, this.selectionRegistrar, this.selectionColor, - }) : assert(maxLines == null || maxLines > 0), - assert(selectionRegistrar == null || selectionColor != null), - assert( - textScaleFactor == 1.0 || identical(textScaler, TextScaler.noScaling), - 'Use textScaler instead.', - ), - textScaler = _effectiveTextScalerFrom(textScaler, textScaleFactor), - super( - children: WidgetSpan.extractFromInlineSpan( - text, - _effectiveTextScalerFrom(textScaler, textScaleFactor), - ), - ); + }) : assert(maxLines == null || maxLines > 0), + assert(selectionRegistrar == null || selectionColor != null), + assert( + textScaleFactor == 1.0 || identical(textScaler, TextScaler.noScaling), + 'Use textScaler instead.', + ), + textScaler = _effectiveTextScalerFrom(textScaler, textScaleFactor), + super( + children: WidgetSpan.extractFromInlineSpan( + text, + _effectiveTextScalerFrom(textScaler, textScaleFactor), + ), + ); static TextScaler _effectiveTextScalerFrom( - TextScaler textScaler, double textScaleFactor) { + TextScaler textScaler, + double textScaleFactor, + ) { return switch ((textScaler, textScaleFactor)) { (final TextScaler scaler, 1.0) => scaler, - (TextScaler.noScaling, final double textScaleFactor) => - TextScaler.linear(textScaleFactor), + (TextScaler.noScaling, final double textScaleFactor) => TextScaler.linear( + textScaleFactor, + ), (final TextScaler scaler, _) => scaler, }; } @@ -269,10 +272,20 @@ class RichText extends MultiChildRenderObjectWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(EnumProperty('textAlign', textAlign, - defaultValue: TextAlign.start)); - properties.add(EnumProperty('textDirection', textDirection, - defaultValue: null)); + properties.add( + EnumProperty( + 'textAlign', + textAlign, + defaultValue: TextAlign.start, + ), + ); + properties.add( + EnumProperty( + 'textDirection', + textDirection, + defaultValue: null, + ), + ); properties.add( FlagProperty( 'softWrap', @@ -283,12 +296,18 @@ class RichText extends MultiChildRenderObjectWidget { ), ); properties.add( - EnumProperty('overflow', overflow, - defaultValue: TextOverflow.clip), + EnumProperty( + 'overflow', + overflow, + defaultValue: TextOverflow.clip, + ), ); properties.add( - DiagnosticsProperty('textScaler', textScaler, - defaultValue: TextScaler.noScaling), + DiagnosticsProperty( + 'textScaler', + textScaler, + defaultValue: TextScaler.noScaling, + ), ); properties.add(IntProperty('maxLines', maxLines, ifNull: 'unlimited')); properties.add( @@ -299,10 +318,16 @@ class RichText extends MultiChildRenderObjectWidget { ), ); properties.add(StringProperty('text', text.toPlainText())); - properties - .add(DiagnosticsProperty('locale', locale, defaultValue: null)); - properties.add(DiagnosticsProperty('strutStyle', strutStyle, - defaultValue: null)); + properties.add( + DiagnosticsProperty('locale', locale, defaultValue: null), + ); + properties.add( + DiagnosticsProperty( + 'strutStyle', + strutStyle, + defaultValue: null, + ), + ); properties.add( DiagnosticsProperty( 'textHeightBehavior', diff --git a/lib/common/widgets/text/text.dart b/lib/common/widgets/text/text.dart index fbbe26c9c..d8a7d9452 100644 --- a/lib/common/widgets/text/text.dart +++ b/lib/common/widgets/text/text.dart @@ -174,11 +174,11 @@ class Text extends StatelessWidget { this.textWidthBasis, this.textHeightBehavior, this.selectionColor, - }) : textSpan = null, - assert( - textScaler == null || textScaleFactor == null, - 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', - ); + }) : textSpan = null, + assert( + textScaler == null || textScaleFactor == null, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ); /// Creates a text widget with a [InlineSpan]. /// @@ -211,11 +211,11 @@ class Text extends StatelessWidget { this.textWidthBasis, this.textHeightBehavior, this.selectionColor, - }) : data = null, - assert( - textScaler == null || textScaleFactor == null, - 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', - ); + }) : data = null, + assert( + textScaler == null || textScaleFactor == null, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ); /// The text to display. /// @@ -357,21 +357,24 @@ class Text extends StatelessWidget { effectiveTextStyle = defaultTextStyle.style.merge(style); } if (MediaQuery.boldTextOf(context)) { - effectiveTextStyle = effectiveTextStyle! - .merge(const TextStyle(fontWeight: FontWeight.bold)); + effectiveTextStyle = effectiveTextStyle!.merge( + const TextStyle(fontWeight: FontWeight.bold), + ); } final SelectionRegistrar? registrar = SelectionContainer.maybeOf(context); final TextScaler textScaler = switch ((this.textScaler, textScaleFactor)) { (final TextScaler textScaler, _) => textScaler, // For unmigrated apps, fall back to textScaleFactor. - (null, final double textScaleFactor) => - TextScaler.linear(textScaleFactor), + (null, final double textScaleFactor) => TextScaler.linear( + textScaleFactor, + ), (null, null) => MediaQuery.textScalerOf(context), }; late Widget result; if (registrar != null) { result = MouseRegion( - cursor: DefaultSelectionStyle.of(context).mouseCursor ?? + cursor: + DefaultSelectionStyle.of(context).mouseCursor ?? SystemMouseCursors.text, child: _SelectableTextContainer( textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start, @@ -380,17 +383,20 @@ class Text extends StatelessWidget { locale: locale, // RichText uses Localizations.localeOf to obtain a default if this is null softWrap: softWrap ?? defaultTextStyle.softWrap, - overflow: overflow ?? + overflow: + overflow ?? effectiveTextStyle?.overflow ?? defaultTextStyle.overflow, textScaler: textScaler, maxLines: maxLines ?? defaultTextStyle.maxLines, strutStyle: strutStyle, textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis, - textHeightBehavior: textHeightBehavior ?? + textHeightBehavior: + textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.maybeOf(context), - selectionColor: selectionColor ?? + selectionColor: + selectionColor ?? DefaultSelectionStyle.of(context).selectionColor ?? DefaultSelectionStyle.defaultColor, text: TextSpan( @@ -408,17 +414,20 @@ class Text extends StatelessWidget { locale: locale, // RichText uses Localizations.localeOf to obtain a default if this is null softWrap: softWrap ?? defaultTextStyle.softWrap, - overflow: overflow ?? + overflow: + overflow ?? effectiveTextStyle?.overflow ?? defaultTextStyle.overflow, textScaler: textScaler, maxLines: maxLines ?? defaultTextStyle.maxLines, strutStyle: strutStyle, textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis, - textHeightBehavior: textHeightBehavior ?? + textHeightBehavior: + textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.maybeOf(context), - selectionColor: selectionColor ?? + selectionColor: + selectionColor ?? DefaultSelectionStyle.of(context).selectionColor ?? DefaultSelectionStyle.defaultColor, text: TextSpan( @@ -433,8 +442,10 @@ class Text extends StatelessWidget { textDirection: textDirection, label: semanticsLabel, identifier: semanticsIdentifier, - child: - ExcludeSemantics(excluding: semanticsLabel != null, child: result), + child: ExcludeSemantics( + excluding: semanticsLabel != null, + child: result, + ), ); } return result; @@ -447,16 +458,25 @@ class Text extends StatelessWidget { if (textSpan != null) { properties.add( textSpan!.toDiagnosticsNode( - name: 'textSpan', style: DiagnosticsTreeStyle.transition), + name: 'textSpan', + style: DiagnosticsTreeStyle.transition, + ), ); } style?.debugFillProperties(properties); properties.add( - EnumProperty('textAlign', textAlign, defaultValue: null)); - properties.add(EnumProperty('textDirection', textDirection, - defaultValue: null)); - properties - .add(DiagnosticsProperty('locale', locale, defaultValue: null)); + EnumProperty('textAlign', textAlign, defaultValue: null), + ); + properties.add( + EnumProperty( + 'textDirection', + textDirection, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty('locale', locale, defaultValue: null), + ); properties.add( FlagProperty( 'softWrap', @@ -467,13 +487,18 @@ class Text extends StatelessWidget { ), ); properties.add( - EnumProperty('overflow', overflow, defaultValue: null)); + EnumProperty('overflow', overflow, defaultValue: null), + ); properties.add( - DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null)); + DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null), + ); properties.add(IntProperty('maxLines', maxLines, defaultValue: null)); properties.add( - EnumProperty('textWidthBasis', textWidthBasis, - defaultValue: null), + EnumProperty( + 'textWidthBasis', + textWidthBasis, + defaultValue: null, + ), ); properties.add( DiagnosticsProperty( @@ -486,8 +511,9 @@ class Text extends StatelessWidget { properties.add(StringProperty('semanticsLabel', semanticsLabel)); } if (semanticsIdentifier != null) { - properties - .add(StringProperty('semanticsIdentifier', semanticsIdentifier)); + properties.add( + StringProperty('semanticsIdentifier', semanticsIdentifier), + ); } } } @@ -653,8 +679,8 @@ class _SelectableTextContainerDelegate // First pass, if the position is on a placeholder then dispatch the selection // event to the [Selectable] at the location and terminate. for (int index = 0; index < selectables.length; index += 1) { - final bool selectableIsPlaceholder = - !paragraph.selectableBelongsToParagraph(selectables[index]); + final bool selectableIsPlaceholder = !paragraph + .selectableBelongsToParagraph(selectables[index]); if (selectableIsPlaceholder && selectables[index].boundingBoxes.isNotEmpty) { for (final Rect rect in selectables[index].boundingBoxes) { @@ -693,8 +719,10 @@ class _SelectableTextContainerDelegate continue; } final SelectionGeometry existingGeometry = selectables[index].value; - lastSelectionResult = - dispatchSelectionEventToChild(selectables[index], event); + lastSelectionResult = dispatchSelectionEventToChild( + selectables[index], + event, + ); if (index == selectables.length - 1 && lastSelectionResult == SelectionResult.next) { if (foundStart) { @@ -711,10 +739,11 @@ class _SelectableTextContainerDelegate if (selectables[index].value != existingGeometry && !foundStart) { assert(selectables[index].boundingBoxes.isNotEmpty); assert(selectables[index].value.selectionRects.isNotEmpty); - final bool selectionAtStartOfSelectable = - selectables[index].boundingBoxes[0].overlaps( - selectables[index].value.selectionRects[0], - ); + final bool selectionAtStartOfSelectable = selectables[index] + .boundingBoxes[0] + .overlaps( + selectables[index].value.selectionRects[0], + ); int startIndex = 0; if (lastNextIndex != null && selectionAtStartOfSelectable) { startIndex = lastNextIndex + 1; @@ -726,9 +755,9 @@ class _SelectableTextContainerDelegate for (int i = startIndex; i < index; i += 1) { final SelectionEvent synthesizedEvent = SelectParagraphSelectionEvent( - globalPosition: event.globalPosition, - absorb: true, - ); + globalPosition: event.globalPosition, + absorb: true, + ); dispatchSelectionEventToChild(selectables[i], synthesizedEvent); } currentSelectionStartIndex = startIndex; @@ -745,9 +774,9 @@ class _SelectableTextContainerDelegate for (int i = 0; i < index; i += 1) { final SelectionEvent synthesizedEvent = SelectParagraphSelectionEvent( - globalPosition: event.globalPosition, - absorb: true, - ); + globalPosition: event.globalPosition, + absorb: true, + ); dispatchSelectionEventToChild(selectables[i], synthesizedEvent); } } @@ -773,8 +802,10 @@ class _SelectableTextContainerDelegate /// Ideally, this method should only be called twice at the beginning of the /// drag selection, once for start edge update event, once for end edge update /// event. - SelectionResult _initSelection(SelectionEdgeUpdateEvent event, - {required bool isEnd}) { + SelectionResult _initSelection( + SelectionEdgeUpdateEvent event, { + required bool isEnd, + }) { assert( (isEnd && currentSelectionEndIndex == -1) || (!isEnd && currentSelectionStartIndex == -1), @@ -804,10 +835,13 @@ class _SelectableTextContainerDelegate // 1. the selectable returns end, pending, none. // 2. the selectable returns previous when looking forward. // 2. the selectable returns next when looking backward. - while ( - newIndex < selectables.length && newIndex >= 0 && finalResult == null) { - currentSelectableResult = - dispatchSelectionEventToChild(selectables[newIndex], event); + while (newIndex < selectables.length && + newIndex >= 0 && + finalResult == null) { + currentSelectableResult = dispatchSelectionEventToChild( + selectables[newIndex], + event, + ); switch (currentSelectableResult) { case SelectionResult.end: case SelectionResult.pending: @@ -844,16 +878,22 @@ class _SelectableTextContainerDelegate return finalResult!; } - SelectionResult _adjustSelection(SelectionEdgeUpdateEvent event, - {required bool isEnd}) { + SelectionResult _adjustSelection( + SelectionEdgeUpdateEvent event, { + required bool isEnd, + }) { assert(() { if (isEnd) { - assert(currentSelectionEndIndex < selectables.length && - currentSelectionEndIndex >= 0); + assert( + currentSelectionEndIndex < selectables.length && + currentSelectionEndIndex >= 0, + ); return true; } - assert(currentSelectionStartIndex < selectables.length && - currentSelectionStartIndex >= 0); + assert( + currentSelectionStartIndex < selectables.length && + currentSelectionStartIndex >= 0, + ); return true; }()); SelectionResult? finalResult; @@ -876,7 +916,7 @@ class _SelectableTextContainerDelegate int newIndex = switch (( isEnd, isCurrentEdgeWithinViewport, - isOppositeEdgeWithinViewport + isOppositeEdgeWithinViewport, )) { (true, true, true) => currentSelectionEndIndex, (true, true, false) => currentSelectionEndIndex, @@ -903,10 +943,13 @@ class _SelectableTextContainerDelegate // 1. the selectable returns end, pending, none. // 2. the selectable returns previous when looking forward. // 2. the selectable returns next when looking backward. - while ( - newIndex < selectables.length && newIndex >= 0 && finalResult == null) { - currentSelectableResult = - dispatchSelectionEventToChild(selectables[newIndex], event); + while (newIndex < selectables.length && + newIndex >= 0 && + finalResult == null) { + currentSelectableResult = dispatchSelectionEventToChild( + selectables[newIndex], + event, + ); switch (currentSelectableResult) { case SelectionResult.end: case SelectionResult.pending: @@ -976,9 +1019,13 @@ class _SelectableTextContainerDelegate // Attempt to sort the selectables under a [_SelectableTextContainerDelegate] // by the top left rect. final Rect rectA = MatrixUtils.transformRect( - a.getTransformTo(null), a.boundingBoxes.first); + a.getTransformTo(null), + a.boundingBoxes.first, + ); final Rect rectB = MatrixUtils.transformRect( - b.getTransformTo(null), b.boundingBoxes.first); + b.getTransformTo(null), + b.boundingBoxes.first, + ); final int result = _compareVertically(rectA, rectB); if (result != 0) { return result; @@ -1045,7 +1092,8 @@ class _SelectableTextContainerDelegate // Use the range from the selectable within the selection as the source of truth for selection direction. final SelectedContentRange rangeAtSelectableInSelection = selectables[currentSelectionStartIndex].getSelection()!; - forwardSelection = rangeAtSelectableInSelection.endOffset >= + forwardSelection = + rangeAtSelectableInSelection.endOffset >= rangeAtSelectableInSelection.startOffset; } for (int index = 0; index < selections.length; index++) { @@ -1073,17 +1121,24 @@ class _SelectableTextContainerDelegate // Because a RenderParagraph may split its content into multiple selectables // we have to consider at what offset a selectable starts at relative // to the RenderParagraph, when the selectable is not the start of the content. - final bool shouldConsiderContentStart = index > 0 && + final bool shouldConsiderContentStart = + index > 0 && paragraph.selectableBelongsToParagraph(selectables[index]); - startOffset += (selectionStartNormalized - - (shouldConsiderContentStart - ? paragraph - .getPositionForOffset( - selectables[index].boundingBoxes.first.centerLeft) - .offset - : 0)) - .abs(); - endOffset = startOffset + + startOffset += + (selectionStartNormalized - + (shouldConsiderContentStart + ? paragraph + .getPositionForOffset( + selectables[index] + .boundingBoxes + .first + .centerLeft, + ) + .offset + : 0)) + .abs(); + endOffset = + startOffset + (selectionEndNormalized - selectionStartNormalized).abs(); foundStart = true; } else { @@ -1111,7 +1166,7 @@ class _SelectableTextContainerDelegate for (final Selectable selectable in selectables) ( contentLength: selectable.contentLength, - range: selectable.getSelection() + range: selectable.getSelection(), ), ]; return _calculateLocalRange(selections); @@ -1138,20 +1193,28 @@ class _SelectableTextContainerDelegate .where((Selectable target) => target != selectables[skipIndex]) .forEach( (Selectable target) => dispatchSelectionEventToChild( - target, const ClearSelectionEvent()), + target, + const ClearSelectionEvent(), + ), ); return; } - final int skipStart = - min(currentSelectionStartIndex, currentSelectionEndIndex); - final int skipEnd = - max(currentSelectionStartIndex, currentSelectionEndIndex); + final int skipStart = min( + currentSelectionStartIndex, + currentSelectionEndIndex, + ); + final int skipEnd = max( + currentSelectionStartIndex, + currentSelectionEndIndex, + ); for (int index = 0; index < selectables.length; index += 1) { if (index >= skipStart && index <= skipEnd) { continue; } dispatchSelectionEventToChild( - selectables[index], const ClearSelectionEvent()); + selectables[index], + const ClearSelectionEvent(), + ); } } diff --git a/lib/common/widgets/text_field/adaptive_text_selection_toolbar.dart b/lib/common/widgets/text_field/adaptive_text_selection_toolbar.dart index 18ede2dc2..6dc0dc393 100644 --- a/lib/common/widgets/text_field/adaptive_text_selection_toolbar.dart +++ b/lib/common/widgets/text_field/adaptive_text_selection_toolbar.dart @@ -62,9 +62,11 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { /// * [AdaptiveTextSelectionToolbar.selectable], which builds the default /// children for content that is selectable but not editable. /// {@endtemplate} - const AdaptiveTextSelectionToolbar( - {super.key, required this.children, required this.anchors}) - : buttonItems = null; + const AdaptiveTextSelectionToolbar({ + super.key, + required this.children, + required this.anchors, + }) : buttonItems = null; /// Create an instance of [AdaptiveTextSelectionToolbar] whose children will /// be built from the given [buttonItems]. @@ -113,18 +115,18 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { required VoidCallback? onShare, required VoidCallback? onLiveTextInput, required this.anchors, - }) : children = null, - buttonItems = EditableText.getEditableButtonItems( - clipboardStatus: clipboardStatus, - onCopy: onCopy, - onCut: onCut, - onPaste: onPaste, - onSelectAll: onSelectAll, - onLookUp: onLookUp, - onSearchWeb: onSearchWeb, - onShare: onShare, - onLiveTextInput: onLiveTextInput, - ); + }) : children = null, + buttonItems = EditableText.getEditableButtonItems( + clipboardStatus: clipboardStatus, + onCopy: onCopy, + onCut: onCut, + onPaste: onPaste, + onSelectAll: onSelectAll, + onLookUp: onLookUp, + onSearchWeb: onSearchWeb, + onShare: onShare, + onLiveTextInput: onLiveTextInput, + ); /// Create an instance of [AdaptiveTextSelectionToolbar] with the default /// children for an [EditableText]. @@ -138,9 +140,9 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { AdaptiveTextSelectionToolbar.editableText({ super.key, required EditableTextState editableTextState, - }) : children = null, - buttonItems = editableTextState.contextMenuButtonItems, - anchors = editableTextState.contextMenuAnchors; + }) : children = null, + buttonItems = editableTextState.contextMenuButtonItems, + anchors = editableTextState.contextMenuAnchors; /// Create an instance of [AdaptiveTextSelectionToolbar] with the default /// children for selectable, but not editable, content. @@ -158,13 +160,13 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { required VoidCallback? onShare, required SelectionGeometry selectionGeometry, required this.anchors, - }) : children = null, - buttonItems = SelectableRegion.getSelectableButtonItems( - selectionGeometry: selectionGeometry, - onCopy: onCopy, - onSelectAll: onSelectAll, - onShare: onShare, - ); + }) : children = null, + buttonItems = SelectableRegion.getSelectableButtonItems( + selectionGeometry: selectionGeometry, + onCopy: onCopy, + onSelectAll: onSelectAll, + onShare: onShare, + ); /// Create an instance of [AdaptiveTextSelectionToolbar] with the default /// children for a [SelectableRegion]. @@ -179,9 +181,9 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { AdaptiveTextSelectionToolbar.selectableRegion({ super.key, required SelectableRegionState selectableRegionState, - }) : children = null, - buttonItems = selectableRegionState.contextMenuButtonItems, - anchors = selectableRegionState.contextMenuAnchors; + }) : children = null, + buttonItems = selectableRegionState.contextMenuButtonItems, + anchors = selectableRegionState.contextMenuAnchors; /// {@template flutter.material.AdaptiveTextSelectionToolbar.buttonItems} /// The [ContextMenuButtonItem]s that will be turned into the correct button @@ -200,7 +202,9 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { /// Returns the default button label String for the button of the given /// [ContextMenuButtonType] on any platform. static String getButtonLabel( - BuildContext context, ContextMenuButtonItem buttonItem) { + BuildContext context, + ContextMenuButtonItem buttonItem, + ) { if (buttonItem.label != null) { return buttonItem.label!; } @@ -209,14 +213,17 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { case TargetPlatform.iOS: case TargetPlatform.macOS: return CupertinoTextSelectionToolbarButton.getButtonLabel( - context, buttonItem); + context, + buttonItem, + ); case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: assert(debugCheckHasMaterialLocalizations(context)); - final MaterialLocalizations localizations = - MaterialLocalizations.of(context); + final MaterialLocalizations localizations = MaterialLocalizations.of( + context, + ); return switch (buttonItem.type) { ContextMenuButtonType.cut => localizations.cutButtonLabel, ContextMenuButtonType.copy => localizations.copyButtonLabel, @@ -261,7 +268,8 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { case TargetPlatform.iOS: return buttonItems.map((ContextMenuButtonItem buttonItem) { return CupertinoTextSelectionToolbarButton.buttonItem( - buttonItem: buttonItem); + buttonItem: buttonItem, + ); }); case TargetPlatform.fuchsia: case TargetPlatform.android: @@ -271,7 +279,9 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { buttons.add( TextSelectionToolbarTextButton( padding: TextSelectionToolbarTextButton.getPadding( - i, buttonItems.length), + i, + buttonItems.length, + ), onPressed: buttonItem.onPressed, alignment: AlignmentDirectional.centerStart, child: Text(getButtonLabel(context, buttonItem)), @@ -331,7 +341,9 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { case TargetPlatform.linux: case TargetPlatform.windows: return DesktopTextSelectionToolbar( - anchor: anchors.primaryAnchor, children: resultChildren); + anchor: anchors.primaryAnchor, + children: resultChildren, + ); case TargetPlatform.macOS: return CupertinoDesktopTextSelectionToolbar( anchor: anchors.primaryAnchor, diff --git a/lib/common/widgets/text_field/controller.dart b/lib/common/widgets/text_field/controller.dart index caa4b32f2..31fc20815 100644 --- a/lib/common/widgets/text_field/controller.dart +++ b/lib/common/widgets/text_field/controller.dart @@ -56,7 +56,7 @@ extension TextEditingDeltaExt on TextEditingDelta { type: composing.isValid ? RichTextType.composing : RichTextType.text, rawText: null, emote: null, - id: null + id: null, ); } @@ -85,7 +85,8 @@ class RichTextEditingDeltaInsertion extends TextEditingDeltaInsertion this.id, this.rawText, }) { - this.type = type ?? + this.type = + type ?? (composing.isValid ? RichTextType.composing : RichTextType.text); } @@ -115,7 +116,8 @@ class RichTextEditingDeltaReplacement extends TextEditingDeltaReplacement this.id, this.rawText, }) { - this.type = type ?? + this.type = + type ?? (composing.isValid ? RichTextType.composing : RichTextType.text); } @@ -305,8 +307,9 @@ class RichTextItem { '', ); range = TextRange(start: range.start, end: range.start + text.length); - controller.newSelection = - TextSelection.collapsed(offset: deletedRange.start); + controller.newSelection = TextSelection.collapsed( + offset: deletedRange.start, + ); return null; } @@ -331,8 +334,9 @@ class RichTextItem { start: range.start, end: deletedRange.start, ); - controller.newSelection = - TextSelection.collapsed(offset: deletedRange.start); + controller.newSelection = TextSelection.collapsed( + offset: deletedRange.start, + ); return null; } @@ -385,11 +389,14 @@ class RichTextItem { final end = range.start + text.length; range = TextRange(start: range.start, end: end); controller.newSelection = TextSelection.collapsed( - offset: replacedRange.start + delta.replacementText.length); + offset: replacedRange.start + delta.replacementText.length, + ); return null; } else { - final leadingText = - text.substring(0, replacedRange.start - range.start); + final leadingText = text.substring( + 0, + replacedRange.start - range.start, + ); final trailString = text.substring(replacedRange.end - range.start); final insertEnd = replacedRange.start + delta.replacementText.length; controller.newSelection = TextSelection.collapsed(offset: insertEnd); @@ -560,10 +567,10 @@ class RichTextEditingController extends TextEditingController { List? items, this.onMention, }) : super( - text: items != null && items.isNotEmpty - ? (StringBuffer()..writeAll(items.map((e) => e.text))).toString() - : null, - ) { + text: items != null && items.isNotEmpty + ? (StringBuffer()..writeAll(items.map((e) => e.text))).toString() + : null, + ) { if (items != null && items.isNotEmpty) { this.items.addAll(items); } @@ -625,8 +632,9 @@ class RichTextEditingController extends TextEditingController { id: config.id, ), ); - newSelection = - TextSelection.collapsed(offset: delta.textInserted.length); + newSelection = TextSelection.collapsed( + offset: delta.textInserted.length, + ); return; } for (int index = 0; index < items.length; index++) { @@ -654,15 +662,17 @@ class RichTextEditingController extends TextEditingController { case TextEditingDeltaReplacement e: for (int index = 0; index < items.length; index++) { final item = items[index]; - ({bool remove, List? toAdd})? res = - item.onReplace(e, this); + ({bool remove, List? toAdd})? res = item.onReplace( + e, + this, + ); if (res != null) { if (res.toAdd != null) { addIndex = res.remove ? index : (e.replacedRange.start == 0 && index == 0) - ? 0 - : index + 1; + ? 0 + : index + 1; (toAdd ??= []).addAll(res.toAdd!); } else if (res.remove) { (toDel ??= []).add(item); @@ -675,7 +685,9 @@ class RichTextEditingController extends TextEditingController { if (newSelection.isCollapsed) { final newPos = dragOffset(newSelection.base); newSelection = newSelection.copyWith( - baseOffset: newPos.offset, extentOffset: newPos.offset); + baseOffset: newPos.offset, + extentOffset: newPos.offset, + ); } else { final isNormalized = newSelection.baseOffset < newSelection.extentOffset; @@ -742,8 +754,10 @@ class RichTextEditingController extends TextEditingController { case RichTextType.text: return TextSpan(text: e.text); case RichTextType.composing: - composingStyle ??= style?.merge( - const TextStyle(decoration: TextDecoration.underline)) ?? + composingStyle ??= + style?.merge( + const TextStyle(decoration: TextDecoration.underline), + ) ?? const TextStyle(decoration: TextDecoration.underline); if (composingRegionOutOfRange) { e.type = RichTextType.text; @@ -753,8 +767,9 @@ class RichTextEditingController extends TextEditingController { style: composingRegionOutOfRange ? null : composingStyle, ); case RichTextType.at || RichTextType.common: - richStyle ??= (style ?? const TextStyle()) - .copyWith(color: Theme.of(context).colorScheme.primary); + richStyle ??= (style ?? const TextStyle()).copyWith( + color: Theme.of(context).colorScheme.primary, + ); return TextSpan( text: e.text, style: richStyle, @@ -778,8 +793,9 @@ class RichTextEditingController extends TextEditingController { } return TextSpan(text: e.text); case RichTextType.vote: - richStyle ??= (style ?? const TextStyle()) - .copyWith(color: Theme.of(context).colorScheme.primary); + richStyle ??= (style ?? const TextStyle()).copyWith( + color: Theme.of(context).colorScheme.primary, + ); return TextSpan( children: [ WidgetSpan( @@ -938,10 +954,14 @@ class RichTextEditingController extends TextEditingController { if (e.isRich) { if (offset < selection.baseOffset) { return newSelection.copyWith( - baseOffset: range.start, extentOffset: range.start); + baseOffset: range.start, + extentOffset: range.start, + ); } else { return newSelection.copyWith( - baseOffset: range.end, extentOffset: range.end); + baseOffset: range.end, + extentOffset: range.end, + ); } } } diff --git a/lib/common/widgets/text_field/cupertino/cupertino_adaptive_text_selection_toolbar.dart b/lib/common/widgets/text_field/cupertino/cupertino_adaptive_text_selection_toolbar.dart index e1311bad4..a29fdf2ce 100644 --- a/lib/common/widgets/text_field/cupertino/cupertino_adaptive_text_selection_toolbar.dart +++ b/lib/common/widgets/text_field/cupertino/cupertino_adaptive_text_selection_toolbar.dart @@ -98,18 +98,18 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { required VoidCallback? onShare, required VoidCallback? onLiveTextInput, required this.anchors, - }) : children = null, - buttonItems = EditableText.getEditableButtonItems( - clipboardStatus: clipboardStatus, - onCopy: onCopy, - onCut: onCut, - onPaste: onPaste, - onSelectAll: onSelectAll, - onLookUp: onLookUp, - onSearchWeb: onSearchWeb, - onShare: onShare, - onLiveTextInput: onLiveTextInput, - ); + }) : children = null, + buttonItems = EditableText.getEditableButtonItems( + clipboardStatus: clipboardStatus, + onCopy: onCopy, + onCut: onCut, + onPaste: onPaste, + onSelectAll: onSelectAll, + onLookUp: onLookUp, + onSearchWeb: onSearchWeb, + onShare: onShare, + onLiveTextInput: onLiveTextInput, + ); /// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the /// default children for an [EditableText]. @@ -125,9 +125,9 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { CupertinoAdaptiveTextSelectionToolbar.editableText({ super.key, required EditableTextState editableTextState, - }) : children = null, - buttonItems = editableTextState.contextMenuButtonItems, - anchors = editableTextState.contextMenuAnchors; + }) : children = null, + buttonItems = editableTextState.contextMenuButtonItems, + anchors = editableTextState.contextMenuAnchors; /// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the /// default children for selectable, but not editable, content. @@ -146,14 +146,13 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { required VoidCallback onSelectAll, required SelectionGeometry selectionGeometry, required this.anchors, - }) : children = null, - buttonItems = SelectableRegion.getSelectableButtonItems( - selectionGeometry: selectionGeometry, - onCopy: onCopy, - onSelectAll: onSelectAll, - onShare: - null, // See https://github.com/flutter/flutter/issues/141775. - ); + }) : children = null, + buttonItems = SelectableRegion.getSelectableButtonItems( + selectionGeometry: selectionGeometry, + onCopy: onCopy, + onSelectAll: onSelectAll, + onShare: null, // See https://github.com/flutter/flutter/issues/141775. + ); /// {@macro flutter.material.AdaptiveTextSelectionToolbar.anchors} final TextSelectionToolbarAnchors anchors; @@ -193,14 +192,16 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { case TargetPlatform.iOS: return buttonItems.map((ContextMenuButtonItem buttonItem) { return CupertinoTextSelectionToolbarButton.buttonItem( - buttonItem: buttonItem); + buttonItem: buttonItem, + ); }); case TargetPlatform.linux: case TargetPlatform.windows: case TargetPlatform.macOS: return buttonItems.map((ContextMenuButtonItem buttonItem) { return CupertinoDesktopTextSelectionToolbarButton.buttonItem( - buttonItem: buttonItem); + buttonItem: buttonItem, + ); }); } } diff --git a/lib/common/widgets/text_field/cupertino/cupertino_spell_check_suggestions_toolbar.dart b/lib/common/widgets/text_field/cupertino/cupertino_spell_check_suggestions_toolbar.dart index 8cce9772b..3a5f6e18c 100644 --- a/lib/common/widgets/text_field/cupertino/cupertino_spell_check_suggestions_toolbar.dart +++ b/lib/common/widgets/text_field/cupertino/cupertino_spell_check_suggestions_toolbar.dart @@ -41,9 +41,9 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget { CupertinoSpellCheckSuggestionsToolbar.editableText({ super.key, required EditableTextState editableTextState, - }) : buttonItems = - buildButtonItems(editableTextState) ?? [], - anchors = editableTextState.contextMenuAnchors; + }) : buttonItems = + buildButtonItems(editableTextState) ?? [], + anchors = editableTextState.contextMenuAnchors; /// The location on which to anchor the menu. final TextSelectionToolbarAnchors anchors; @@ -66,12 +66,13 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget { /// Builds the button items for the toolbar based on the available /// spell check suggestions. static List? buildButtonItems( - EditableTextState editableTextState) { + EditableTextState editableTextState, + ) { // Determine if composing region is misspelled. - final SuggestionSpan? spanAtCursorIndex = - editableTextState.findSuggestionSpanAtCursorIndex( - editableTextState.currentTextEditingValue.selection.baseOffset, - ); + final SuggestionSpan? spanAtCursorIndex = editableTextState + .findSuggestionSpanAtCursorIndex( + editableTextState.currentTextEditingValue.selection.baseOffset, + ); if (spanAtCursorIndex == null) { return null; @@ -83,16 +84,18 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget { ); return [ ContextMenuButtonItem( - onPressed: null, - label: localizations.noSpellCheckReplacementsLabel), + onPressed: null, + label: localizations.noSpellCheckReplacementsLabel, + ), ]; } final List buttonItems = []; // Build suggestion buttons. - for (final String suggestion - in spanAtCursorIndex.suggestions.take(_kMaxSuggestions)) { + for (final String suggestion in spanAtCursorIndex.suggestions.take( + _kMaxSuggestions, + )) { buttonItems.add( ContextMenuButtonItem( onPressed: () { @@ -100,7 +103,10 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget { return; } _replaceText( - editableTextState, suggestion, spanAtCursorIndex.range); + editableTextState, + suggestion, + spanAtCursorIndex.range, + ); }, label: suggestion, ), @@ -115,22 +121,29 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget { TextRange replacementRange, ) { // Replacement cannot be performed if the text is read only or obscured. - assert(!editableTextState.widget.readOnly && - !editableTextState.widget.obscureText); + assert( + !editableTextState.widget.readOnly && + !editableTextState.widget.obscureText, + ); final TextEditingValue newValue = editableTextState.textEditingValue .replaced(replacementRange, text) .copyWith( - selection: TextSelection.collapsed( - offset: replacementRange.start + text.length)); + selection: TextSelection.collapsed( + offset: replacementRange.start + text.length, + ), + ); editableTextState.userUpdateTextEditingValue( - newValue, SelectionChangedCause.toolbar); + newValue, + SelectionChangedCause.toolbar, + ); // Schedule a call to bringIntoView() after renderEditable updates. SchedulerBinding.instance.addPostFrameCallback((Duration duration) { if (editableTextState.mounted) { - editableTextState - .bringIntoView(editableTextState.textEditingValue.selection.extent); + editableTextState.bringIntoView( + editableTextState.textEditingValue.selection.extent, + ); } }, debugLabel: 'SpellCheckSuggestions.bringIntoView'); editableTextState.hideToolbar(); @@ -140,7 +153,8 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget { List _buildToolbarButtons(BuildContext context) { return buttonItems.map((ContextMenuButtonItem buttonItem) { return CupertinoTextSelectionToolbarButton.buttonItem( - buttonItem: buttonItem); + buttonItem: buttonItem, + ); }).toList(); } diff --git a/lib/common/widgets/text_field/cupertino/cupertino_text_field.dart b/lib/common/widgets/text_field/cupertino/cupertino_text_field.dart index 7b449ccbd..705df17ea 100644 --- a/lib/common/widgets/text_field/cupertino/cupertino_text_field.dart +++ b/lib/common/widgets/text_field/cupertino/cupertino_text_field.dart @@ -77,9 +77,9 @@ const Color _kDisabledBackground = CupertinoDynamicColor.withBrightness( // Note it may not be consistent with https://developer.apple.com/design/resources/. const CupertinoDynamicColor _kClearButtonColor = CupertinoDynamicColor.withBrightness( - color: Color(0x33000000), - darkColor: Color(0x33FFFFFF), -); + color: Color(0x33000000), + darkColor: Color(0x33FFFFFF), + ); // An eyeballed value that moves the cursor slightly left of where it is // rendered for text on Android so it's positioning more accurately matches the @@ -115,10 +115,10 @@ enum OverlayVisibilityMode { class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDetectorBuilder { - _CupertinoTextFieldSelectionGestureDetectorBuilder( - {required _CupertinoRichTextFieldState state}) - : _state = state, - super(delegate: state); + _CupertinoTextFieldSelectionGestureDetectorBuilder({ + required _CupertinoRichTextFieldState state, + }) : _state = state, + super(delegate: state); final _CupertinoRichTextFieldState _state; @@ -129,10 +129,12 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder // this handler. If the clear button widget recognizes the up event, // then do not handle it. if (_state._clearGlobalKey.currentContext != null) { - final RenderBox renderBox = _state._clearGlobalKey.currentContext! - .findRenderObject()! as RenderBox; - final Offset localOffset = - renderBox.globalToLocal(details.globalPosition); + final RenderBox renderBox = + _state._clearGlobalKey.currentContext!.findRenderObject()! + as RenderBox; + final Offset localOffset = renderBox.globalToLocal( + details.globalPosition, + ); if (renderBox.hitTest(BoxHitTestResult(), position: localOffset)) { return; } @@ -324,35 +326,40 @@ class CupertinoRichTextField extends StatefulWidget { this.contextMenuBuilder = _defaultContextMenuBuilder, this.spellCheckConfiguration, this.magnifierConfiguration, - }) : assert(obscuringCharacter.length == 1), - smartDashesType = smartDashesType ?? - (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), - smartQuotesType = smartQuotesType ?? - (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), - assert(maxLines == null || maxLines > 0), - assert(minLines == null || minLines > 0), - assert( - (maxLines == null) || (minLines == null) || (maxLines >= minLines), - "minLines can't be greater than maxLines", - ), - assert( - !expands || (maxLines == null && minLines == null), - 'minLines and maxLines must be null when expands is true.', - ), - assert(!obscureText || maxLines == 1, - 'Obscured fields cannot be multiline.'), - assert(maxLength == null || maxLength > 0), - // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. - assert( - !identical(textInputAction, TextInputAction.newline) || - maxLines == 1 || - !identical(keyboardType, TextInputType.text), - 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', - ), - keyboardType = keyboardType ?? - (maxLines == 1 ? TextInputType.text : TextInputType.multiline), - enableInteractiveSelection = - enableInteractiveSelection ?? (!readOnly || !obscureText); + }) : assert(obscuringCharacter.length == 1), + smartDashesType = + smartDashesType ?? + (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), + smartQuotesType = + smartQuotesType ?? + (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), + assert(maxLines == null || maxLines > 0), + assert(minLines == null || minLines > 0), + assert( + (maxLines == null) || (minLines == null) || (maxLines >= minLines), + "minLines can't be greater than maxLines", + ), + assert( + !expands || (maxLines == null && minLines == null), + 'minLines and maxLines must be null when expands is true.', + ), + assert( + !obscureText || maxLines == 1, + 'Obscured fields cannot be multiline.', + ), + assert(maxLength == null || maxLength > 0), + // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. + assert( + !identical(textInputAction, TextInputAction.newline) || + maxLines == 1 || + !identical(keyboardType, TextInputType.text), + 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', + ), + keyboardType = + keyboardType ?? + (maxLines == 1 ? TextInputType.text : TextInputType.multiline), + enableInteractiveSelection = + enableInteractiveSelection ?? (!readOnly || !obscureText); /// Creates a borderless iOS-style text field. /// @@ -464,35 +471,40 @@ class CupertinoRichTextField extends StatefulWidget { this.contextMenuBuilder = _defaultContextMenuBuilder, this.spellCheckConfiguration, this.magnifierConfiguration, - }) : assert(obscuringCharacter.length == 1), - smartDashesType = smartDashesType ?? - (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), - smartQuotesType = smartQuotesType ?? - (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), - assert(maxLines == null || maxLines > 0), - assert(minLines == null || minLines > 0), - assert( - (maxLines == null) || (minLines == null) || (maxLines >= minLines), - "minLines can't be greater than maxLines", - ), - assert( - !expands || (maxLines == null && minLines == null), - 'minLines and maxLines must be null when expands is true.', - ), - assert(!obscureText || maxLines == 1, - 'Obscured fields cannot be multiline.'), - assert(maxLength == null || maxLength > 0), - // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. - assert( - !identical(textInputAction, TextInputAction.newline) || - maxLines == 1 || - !identical(keyboardType, TextInputType.text), - 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', - ), - keyboardType = keyboardType ?? - (maxLines == 1 ? TextInputType.text : TextInputType.multiline), - enableInteractiveSelection = - enableInteractiveSelection ?? (!readOnly || !obscureText); + }) : assert(obscuringCharacter.length == 1), + smartDashesType = + smartDashesType ?? + (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), + smartQuotesType = + smartQuotesType ?? + (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), + assert(maxLines == null || maxLines > 0), + assert(minLines == null || minLines > 0), + assert( + (maxLines == null) || (minLines == null) || (maxLines >= minLines), + "minLines can't be greater than maxLines", + ), + assert( + !expands || (maxLines == null && minLines == null), + 'minLines and maxLines must be null when expands is true.', + ), + assert( + !obscureText || maxLines == 1, + 'Obscured fields cannot be multiline.', + ), + assert(maxLength == null || maxLength > 0), + // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. + assert( + !identical(textInputAction, TextInputAction.newline) || + maxLines == 1 || + !identical(keyboardType, TextInputType.text), + 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', + ), + keyboardType = + keyboardType ?? + (maxLines == 1 ? TextInputType.text : TextInputType.multiline), + enableInteractiveSelection = + enableInteractiveSelection ?? (!readOnly || !obscureText); /// {@macro flutter.widgets.editableText.groupId} final Object groupId; @@ -832,10 +844,12 @@ class CupertinoRichTextField extends StatefulWidget { if (defaultTargetPlatform == TargetPlatform.iOS && SystemContextMenu.isSupported(context)) { return SystemContextMenu.editableText( - editableTextState: editableTextState); + editableTextState: editableTextState, + ); } return CupertinoAdaptiveTextSelectionToolbar.editableText( - editableTextState: editableTextState); + editableTextState: editableTextState, + ); } /// Configuration for the text field magnifier. @@ -895,7 +909,8 @@ class CupertinoRichTextField extends StatefulWidget { EditableTextState editableTextState, ) { return CupertinoSpellCheckSuggestionsToolbar.editableText( - editableTextState: editableTextState); + editableTextState: editableTextState, + ); } /// {@macro flutter.widgets.undoHistory.controller} @@ -908,11 +923,19 @@ class CupertinoRichTextField extends StatefulWidget { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add( - DiagnosticsProperty('controller', controller, - defaultValue: null), + DiagnosticsProperty( + 'controller', + controller, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty( + 'focusNode', + focusNode, + defaultValue: null, + ), ); - properties.add(DiagnosticsProperty('focusNode', focusNode, - defaultValue: null)); properties.add( DiagnosticsProperty( 'undoController', @@ -920,25 +943,37 @@ class CupertinoRichTextField extends StatefulWidget { defaultValue: null, ), ); - properties - .add(DiagnosticsProperty('decoration', decoration)); + properties.add( + DiagnosticsProperty('decoration', decoration), + ); properties.add(DiagnosticsProperty('padding', padding)); properties.add(StringProperty('placeholder', placeholder)); properties.add( - DiagnosticsProperty('placeholderStyle', placeholderStyle)); - properties.add( - DiagnosticsProperty( - 'prefix', prefix == null ? null : prefixMode), + DiagnosticsProperty('placeholderStyle', placeholderStyle), ); properties.add( DiagnosticsProperty( - 'suffix', suffix == null ? null : suffixMode), + 'prefix', + prefix == null ? null : prefixMode, + ), + ); + properties.add( + DiagnosticsProperty( + 'suffix', + suffix == null ? null : suffixMode, + ), + ); + properties.add( + DiagnosticsProperty( + 'clearButtonMode', + clearButtonMode, + ), ); - properties.add(DiagnosticsProperty( - 'clearButtonMode', clearButtonMode)); properties.add( DiagnosticsProperty( - 'clearButtonSemanticLabel', clearButtonSemanticLabel), + 'clearButtonSemanticLabel', + clearButtonSemanticLabel, + ), ); properties.add( DiagnosticsProperty( @@ -948,41 +983,58 @@ class CupertinoRichTextField extends StatefulWidget { ), ); properties.add( - DiagnosticsProperty('style', style, defaultValue: null)); - properties.add( - DiagnosticsProperty('autofocus', autofocus, defaultValue: false)); - properties.add( - DiagnosticsProperty('obscuringCharacter', obscuringCharacter, - defaultValue: '•'), + DiagnosticsProperty('style', style, defaultValue: null), + ); + properties.add( + DiagnosticsProperty('autofocus', autofocus, defaultValue: false), + ); + properties.add( + DiagnosticsProperty( + 'obscuringCharacter', + obscuringCharacter, + defaultValue: '•', + ), + ); + properties.add( + DiagnosticsProperty( + 'obscureText', + obscureText, + defaultValue: false, + ), + ); + properties.add( + DiagnosticsProperty('autocorrect', autocorrect, defaultValue: true), ); - properties.add(DiagnosticsProperty('obscureText', obscureText, - defaultValue: false)); - properties.add(DiagnosticsProperty('autocorrect', autocorrect, - defaultValue: true)); properties.add( EnumProperty( 'smartDashesType', smartDashesType, - defaultValue: - obscureText ? SmartDashesType.disabled : SmartDashesType.enabled, + defaultValue: obscureText + ? SmartDashesType.disabled + : SmartDashesType.enabled, ), ); properties.add( EnumProperty( 'smartQuotesType', smartQuotesType, - defaultValue: - obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled, + defaultValue: obscureText + ? SmartQuotesType.disabled + : SmartQuotesType.enabled, ), ); properties.add( - DiagnosticsProperty('enableSuggestions', enableSuggestions, - defaultValue: true), + DiagnosticsProperty( + 'enableSuggestions', + enableSuggestions, + defaultValue: true, + ), ); properties.add(IntProperty('maxLines', maxLines, defaultValue: 1)); properties.add(IntProperty('minLines', minLines, defaultValue: null)); properties.add( - DiagnosticsProperty('expands', expands, defaultValue: false)); + DiagnosticsProperty('expands', expands, defaultValue: false), + ); properties.add(IntProperty('maxLength', maxLength, defaultValue: null)); properties.add( EnumProperty( @@ -991,18 +1043,33 @@ class CupertinoRichTextField extends StatefulWidget { defaultValue: null, ), ); - properties - .add(DoubleProperty('cursorWidth', cursorWidth, defaultValue: 2.0)); - properties - .add(DoubleProperty('cursorHeight', cursorHeight, defaultValue: null)); - properties.add(DiagnosticsProperty('cursorRadius', cursorRadius, - defaultValue: null)); properties.add( - DiagnosticsProperty('cursorOpacityAnimates', cursorOpacityAnimates, - defaultValue: true), + DoubleProperty('cursorWidth', cursorWidth, defaultValue: 2.0), + ); + properties.add( + DoubleProperty('cursorHeight', cursorHeight, defaultValue: null), + ); + properties.add( + DiagnosticsProperty( + 'cursorRadius', + cursorRadius, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty( + 'cursorOpacityAnimates', + cursorOpacityAnimates, + defaultValue: true, + ), + ); + properties.add( + createCupertinoColorProperty( + 'cursorColor', + cursorColor, + defaultValue: null, + ), ); - properties.add(createCupertinoColorProperty('cursorColor', cursorColor, - defaultValue: null)); properties.add( FlagProperty( 'selectionEnabled', @@ -1026,11 +1093,19 @@ class CupertinoRichTextField extends StatefulWidget { ), ); properties.add( - DiagnosticsProperty('scrollPhysics', scrollPhysics, - defaultValue: null), + DiagnosticsProperty( + 'scrollPhysics', + scrollPhysics, + defaultValue: null, + ), + ); + properties.add( + EnumProperty( + 'textAlign', + textAlign, + defaultValue: TextAlign.start, + ), ); - properties.add(EnumProperty('textAlign', textAlign, - defaultValue: TextAlign.start)); properties.add( DiagnosticsProperty( 'textAlignVertical', @@ -1038,15 +1113,26 @@ class CupertinoRichTextField extends StatefulWidget { defaultValue: null, ), ); - properties.add(EnumProperty('textDirection', textDirection, - defaultValue: null)); properties.add( - DiagnosticsProperty('clipBehavior', clipBehavior, - defaultValue: Clip.hardEdge), + EnumProperty( + 'textDirection', + textDirection, + defaultValue: null, + ), ); properties.add( - DiagnosticsProperty('scribbleEnabled', scribbleEnabled, - defaultValue: true), + DiagnosticsProperty( + 'clipBehavior', + clipBehavior, + defaultValue: Clip.hardEdge, + ), + ); + properties.add( + DiagnosticsProperty( + 'scribbleEnabled', + scribbleEnabled, + defaultValue: true, + ), ); properties.add( DiagnosticsProperty( @@ -1082,24 +1168,27 @@ class CupertinoRichTextField extends StatefulWidget { static final TextMagnifierConfiguration _iosMagnifierConfiguration = TextMagnifierConfiguration( - magnifierBuilder: ( - BuildContext context, - MagnifierController controller, - ValueNotifier magnifierInfo, - ) { - switch (defaultTargetPlatform) { - case TargetPlatform.android: - case TargetPlatform.iOS: - return CupertinoTextMagnifier( - controller: controller, magnifierInfo: magnifierInfo); - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.macOS: - case TargetPlatform.windows: - return null; - } - }, - ); + magnifierBuilder: + ( + BuildContext context, + MagnifierController controller, + ValueNotifier magnifierInfo, + ) { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + case TargetPlatform.iOS: + return CupertinoTextMagnifier( + controller: controller, + magnifierInfo: magnifierInfo, + ); + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.macOS: + case TargetPlatform.windows: + return null; + } + }, + ); /// Returns a new [SpellCheckConfiguration] where the given configuration has /// had any missing values replaced with their defaults for the iOS platform. @@ -1112,13 +1201,15 @@ class CupertinoRichTextField extends StatefulWidget { } return configuration.copyWith( - misspelledTextStyle: configuration.misspelledTextStyle ?? + misspelledTextStyle: + configuration.misspelledTextStyle ?? CupertinoRichTextField.cupertinoMisspelledTextStyle, - misspelledSelectionColor: configuration.misspelledSelectionColor ?? + misspelledSelectionColor: + configuration.misspelledSelectionColor ?? CupertinoRichTextField.kMisspelledSelectionColor, spellCheckSuggestionsToolbarBuilder: configuration.spellCheckSuggestionsToolbarBuilder ?? - CupertinoRichTextField.defaultSpellCheckSuggestionsToolbarBuilder, + CupertinoRichTextField.defaultSpellCheckSuggestionsToolbarBuilder, ); } } @@ -1143,7 +1234,7 @@ class _CupertinoRichTextFieldState extends State bool _showSelectionHandles = false; late _CupertinoTextFieldSelectionGestureDetectorBuilder - _selectionGestureDetectorBuilder; + _selectionGestureDetectorBuilder; // API for TextSelectionGestureDetectorBuilderDelegate. @override @@ -1162,8 +1253,8 @@ class _CupertinoRichTextFieldState extends State super.initState(); _selectionGestureDetectorBuilder = _CupertinoTextFieldSelectionGestureDetectorBuilder( - state: this, - ); + state: this, + ); // if (widget.controller == null) { // _createLocalController(); // } @@ -1264,7 +1355,9 @@ class _CupertinoRichTextFieldState extends State } void _handleSelectionChanged( - TextSelection selection, SelectionChangedCause? cause) { + TextSelection selection, + SelectionChangedCause? cause, + ) { final bool willShowSelectionHandles = _shouldShowSelectionHandles(cause); if (willShowSelectionHandles != _showSelectionHandles) { setState(() { @@ -1343,7 +1436,8 @@ class _CupertinoRichTextFieldState extends State } Widget _buildClearButton() { - final String clearLabel = widget.clearButtonSemanticLabel ?? + final String clearLabel = + widget.clearButtonSemanticLabel ?? CupertinoLocalizations.of(context).clearButtonLabel; return Semantics( @@ -1410,8 +1504,11 @@ class _CupertinoRichTextFieldState extends State ), ); - final Widget? prefixWidget = _shouldShowAttachment( - attachment: widget.prefixMode, hasText: hasText) + final Widget? prefixWidget = + _shouldShowAttachment( + attachment: widget.prefixMode, + hasText: hasText, + ) ? widget.prefix : null; @@ -1424,8 +1521,10 @@ class _CupertinoRichTextFieldState extends State attachment: widget.clearButtonMode, hasText: hasText, ); - final Widget? suffixWidget = - switch ((showUserSuffix, showClearButton)) { + final Widget? suffixWidget = switch (( + showUserSuffix, + showClearButton, + )) { (false, false) => null, (true, false) => widget.suffix, (true, true) => widget.suffix ?? _buildClearButton(), @@ -1447,10 +1546,7 @@ class _CupertinoRichTextFieldState extends State // See also https://github.com/flutter/flutter/issues/13715. alignment: AlignmentDirectional.center, textDirection: widget.textDirection, - children: [ - ?placeholder, - editableText - ], + children: [?placeholder, editableText], ), ), ?suffixWidget, @@ -1470,8 +1566,9 @@ class _CupertinoRichTextFieldState extends State @override TextInputConfiguration get textInputConfiguration { - final List? autofillHints = - widget.autofillHints?.toList(growable: false); + final List? autofillHints = widget.autofillHints?.toList( + growable: false, + ); final AutofillConfiguration autofillConfiguration = autofillHints != null ? AutofillConfiguration( uniqueIdentifier: autofillId, @@ -1535,35 +1632,44 @@ class _CupertinoRichTextFieldState extends State final TextStyle? resolvedStyle = widget.style?.copyWith( color: CupertinoDynamicColor.maybeResolve(widget.style?.color, context), backgroundColor: CupertinoDynamicColor.maybeResolve( - widget.style?.backgroundColor, context), - ); - - final TextStyle textStyle = - themeData.textTheme.textStyle.merge(resolvedStyle); - - final TextStyle? resolvedPlaceholderStyle = - widget.placeholderStyle?.copyWith( - color: CupertinoDynamicColor.maybeResolve( - widget.placeholderStyle?.color, context), - backgroundColor: CupertinoDynamicColor.maybeResolve( - widget.placeholderStyle?.backgroundColor, + widget.style?.backgroundColor, context, ), ); - final TextStyle placeholderStyle = - textStyle.merge(resolvedPlaceholderStyle); + final TextStyle textStyle = themeData.textTheme.textStyle.merge( + resolvedStyle, + ); + + final TextStyle? resolvedPlaceholderStyle = widget.placeholderStyle + ?.copyWith( + color: CupertinoDynamicColor.maybeResolve( + widget.placeholderStyle?.color, + context, + ), + backgroundColor: CupertinoDynamicColor.maybeResolve( + widget.placeholderStyle?.backgroundColor, + context, + ), + ); + + final TextStyle placeholderStyle = textStyle.merge( + resolvedPlaceholderStyle, + ); final Brightness keyboardAppearance = widget.keyboardAppearance ?? CupertinoTheme.brightnessOf(context); - final Color cursorColor = CupertinoDynamicColor.maybeResolve( + final Color cursorColor = + CupertinoDynamicColor.maybeResolve( widget.cursorColor ?? DefaultSelectionStyle.of(context).cursorColor, context, ) ?? themeData.primaryColor; - final Color disabledColor = - CupertinoDynamicColor.resolve(_kDisabledBackground, context); + final Color disabledColor = CupertinoDynamicColor.resolve( + _kDisabledBackground, + context, + ); final Color? decorationColor = CupertinoDynamicColor.maybeResolve( widget.decoration?.color, @@ -1577,7 +1683,8 @@ class _CupertinoRichTextFieldState extends State return side == BorderSide.none ? side : side.copyWith( - color: CupertinoDynamicColor.resolve(side.color, context)); + color: CupertinoDynamicColor.resolve(side.color, context), + ); } resolvedBorder = border.runtimeType != Border @@ -1596,11 +1703,12 @@ class _CupertinoRichTextFieldState extends State color: enabled ? decorationColor : (widget.decoration == _kDefaultRoundedBorderDecoration - ? disabledColor - : widget.decoration?.color), + ? disabledColor + : widget.decoration?.color), ); - final Color selectionColor = CupertinoDynamicColor.maybeResolve( + final Color selectionColor = + CupertinoDynamicColor.maybeResolve( DefaultSelectionStyle.of(context).selectionColor, context, ) ?? @@ -1611,7 +1719,8 @@ class _CupertinoRichTextFieldState extends State // unless a custom style is specified. final SpellCheckConfiguration spellCheckConfiguration = CupertinoRichTextField.inferIOSSpellCheckConfiguration( - widget.spellCheckConfiguration); + widget.spellCheckConfiguration, + ); final Widget paddedEditable = Padding( padding: widget.padding, @@ -1644,13 +1753,16 @@ class _CupertinoRichTextFieldState extends State maxLines: widget.maxLines, minLines: widget.minLines, expands: widget.expands, - magnifierConfiguration: widget.magnifierConfiguration ?? + magnifierConfiguration: + widget.magnifierConfiguration ?? CupertinoRichTextField._iosMagnifierConfiguration, // Only show the selection highlight when the text field is focused. - selectionColor: - _effectiveFocusNode.hasFocus ? selectionColor : null, - selectionControls: - widget.selectionEnabled ? textSelectionControls : null, + selectionColor: _effectiveFocusNode.hasFocus + ? selectionColor + : null, + selectionControls: widget.selectionEnabled + ? textSelectionControls + : null, groupId: widget.groupId, onChanged: widget.onChanged, onSelectionChanged: _handleSelectionChanged, @@ -1699,8 +1811,9 @@ class _CupertinoRichTextFieldState extends State ? null : () { if (!controller.selection.isValid) { - controller.selection = - TextSelection.collapsed(offset: controller.text.length); + controller.selection = TextSelection.collapsed( + offset: controller.text.length, + ); } _requestKeyboard(); }, @@ -1741,8 +1854,9 @@ class _CupertinoRichTextFieldState extends State ignoring: !enabled, child: Container( decoration: effectiveDecoration, - color: - !enabled && effectiveDecoration == null ? disabledColor : null, + color: !enabled && effectiveDecoration == null + ? disabledColor + : null, child: _selectionGestureDetectorBuilder.buildGestureDetector( behavior: HitTestBehavior.translucent, child: Align( @@ -1750,7 +1864,10 @@ class _CupertinoRichTextFieldState extends State widthFactor: 1.0, heightFactor: 1.0, child: _addTextDependentAttachments( - paddedEditable, textStyle, placeholderStyle), + paddedEditable, + textStyle, + placeholderStyle, + ), ), ), ), diff --git a/lib/common/widgets/text_field/editable.dart b/lib/common/widgets/text_field/editable.dart index 5751522a1..4e3af69e4 100644 --- a/lib/common/widgets/text_field/editable.dart +++ b/lib/common/widgets/text_field/editable.dart @@ -7,7 +7,8 @@ library; import 'dart:collection'; import 'dart:math' as math; -import 'dart:ui' as ui +import 'dart:ui' + as ui show BoxHeightStyle, BoxWidthStyle, @@ -122,8 +123,8 @@ class VerticalCaretMovementRun implements Iterator { if (!_isValid) { return false; } - final List newLineMetrics = - _editable._textPainter.computeLineMetrics(); + final List newLineMetrics = _editable._textPainter + .computeLineMetrics(); // Use the implementation detail of the computeLineMetrics method to figure // out if the current text layout has been invalidated. if (!identical(newLineMetrics, _lineMetrics)) { @@ -149,8 +150,8 @@ class VerticalCaretMovementRun implements Iterator { _currentOffset.dx, _lineMetrics[lineNumber].baseline, ); - final TextPosition closestPosition = - _editable._textPainter.getPositionForOffset(newOffset); + final TextPosition closestPosition = _editable._textPainter + .getPositionForOffset(newOffset); final MapEntry position = MapEntry(newOffset, closestPosition); _positionCache[lineNumber] = position; @@ -305,56 +306,56 @@ class RenderEditable extends RenderBox RenderEditablePainter? foregroundPainter, List? children, required this.controller, - }) : assert(maxLines == null || maxLines > 0), - assert(minLines == null || minLines > 0), - assert( - (maxLines == null) || (minLines == null) || (maxLines >= minLines), - "minLines can't be greater than maxLines", - ), - assert( - !expands || (maxLines == null && minLines == null), - 'minLines and maxLines must be null when expands is true.', - ), - assert( - identical(textScaler, TextScaler.noScaling) || textScaleFactor == 1.0, - 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', - ), - assert(obscuringCharacter.characters.length == 1), - assert(cursorWidth >= 0.0), - assert(cursorHeight == null || cursorHeight >= 0.0), - _textPainter = TextPainter( - text: text, - textAlign: textAlign, - textDirection: textDirection, - textScaler: textScaler == TextScaler.noScaling - ? TextScaler.linear(textScaleFactor) - : textScaler, - locale: locale, - maxLines: maxLines == 1 ? 1 : null, - strutStyle: strutStyle, - textHeightBehavior: textHeightBehavior, - textWidthBasis: textWidthBasis, - ), - _showCursor = showCursor ?? ValueNotifier(false), - _maxLines = maxLines, - _minLines = minLines, - _expands = expands, - _selection = selection, - _offset = offset, - _cursorWidth = cursorWidth, - _cursorHeight = cursorHeight, - _paintCursorOnTop = paintCursorAboveText, - _enableInteractiveSelection = enableInteractiveSelection, - _devicePixelRatio = devicePixelRatio, - _startHandleLayerLink = startHandleLayerLink, - _endHandleLayerLink = endHandleLayerLink, - _obscuringCharacter = obscuringCharacter, - _obscureText = obscureText, - _readOnly = readOnly, - _forceLine = forceLine, - _clipBehavior = clipBehavior, - _hasFocus = hasFocus ?? false, - _disposeShowCursor = showCursor == null { + }) : assert(maxLines == null || maxLines > 0), + assert(minLines == null || minLines > 0), + assert( + (maxLines == null) || (minLines == null) || (maxLines >= minLines), + "minLines can't be greater than maxLines", + ), + assert( + !expands || (maxLines == null && minLines == null), + 'minLines and maxLines must be null when expands is true.', + ), + assert( + identical(textScaler, TextScaler.noScaling) || textScaleFactor == 1.0, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ), + assert(obscuringCharacter.characters.length == 1), + assert(cursorWidth >= 0.0), + assert(cursorHeight == null || cursorHeight >= 0.0), + _textPainter = TextPainter( + text: text, + textAlign: textAlign, + textDirection: textDirection, + textScaler: textScaler == TextScaler.noScaling + ? TextScaler.linear(textScaleFactor) + : textScaler, + locale: locale, + maxLines: maxLines == 1 ? 1 : null, + strutStyle: strutStyle, + textHeightBehavior: textHeightBehavior, + textWidthBasis: textWidthBasis, + ), + _showCursor = showCursor ?? ValueNotifier(false), + _maxLines = maxLines, + _minLines = minLines, + _expands = expands, + _selection = selection, + _offset = offset, + _cursorWidth = cursorWidth, + _cursorHeight = cursorHeight, + _paintCursorOnTop = paintCursorAboveText, + _enableInteractiveSelection = enableInteractiveSelection, + _devicePixelRatio = devicePixelRatio, + _startHandleLayerLink = startHandleLayerLink, + _endHandleLayerLink = endHandleLayerLink, + _obscuringCharacter = obscuringCharacter, + _obscureText = obscureText, + _readOnly = readOnly, + _forceLine = forceLine, + _clipBehavior = clipBehavior, + _hasFocus = hasFocus ?? false, + _disposeShowCursor = showCursor == null { assert(!_showCursor.value || cursorColor != null); _selectionPainter.highlightColor = selectionColor; @@ -1503,15 +1504,15 @@ class RenderEditable extends RenderBox switch (info.recognizer) { case TapGestureRecognizer(onTap: final VoidCallback? handler): case DoubleTapGestureRecognizer( - onDoubleTap: final VoidCallback? handler, - ): + onDoubleTap: final VoidCallback? handler, + ): if (handler != null) { configuration.onTap = handler; configuration.isLink = true; } case LongPressGestureRecognizer( - onLongPress: final GestureLongPressCallback? onLongPress, - ): + onLongPress: final GestureLongPressCallback? onLongPress, + ): if (onLongPress != null) { configuration.onLongPress = onLongPress; } @@ -1570,8 +1571,9 @@ class RenderEditable extends RenderBox if (extentOffset == null) { return; } - final int baseOffset = - !extendSelection ? extentOffset : selection!.baseOffset; + final int baseOffset = !extendSelection + ? extentOffset + : selection!.baseOffset; _setSelection( TextSelection(baseOffset: baseOffset, extentOffset: extentOffset), SelectionChangedCause.keyboard, @@ -1586,8 +1588,9 @@ class RenderEditable extends RenderBox if (extentOffset == null) { return; } - final int baseOffset = - !extendSelection ? extentOffset : selection!.baseOffset; + final int baseOffset = !extendSelection + ? extentOffset + : selection!.baseOffset; _setSelection( TextSelection(baseOffset: baseOffset, extentOffset: extentOffset), SelectionChangedCause.keyboard, @@ -1603,8 +1606,9 @@ class RenderEditable extends RenderBox if (nextWord == null) { return; } - final int baseOffset = - extendSelection ? selection!.baseOffset : nextWord.start; + final int baseOffset = extendSelection + ? selection!.baseOffset + : nextWord.start; _setSelection( TextSelection(baseOffset: baseOffset, extentOffset: nextWord.start), SelectionChangedCause.keyboard, @@ -1620,8 +1624,9 @@ class RenderEditable extends RenderBox if (previousWord == null) { return; } - final int baseOffset = - extendSelection ? selection!.baseOffset : previousWord.start; + final int baseOffset = extendSelection + ? selection!.baseOffset + : previousWord.start; _setSelection( TextSelection(baseOffset: baseOffset, extentOffset: previousWord.start), SelectionChangedCause.keyboard, @@ -1733,9 +1738,9 @@ class RenderEditable extends RenderBox Axis get _viewportAxis => _isMultiline ? Axis.vertical : Axis.horizontal; Offset get _paintOffset => switch (_viewportAxis) { - Axis.horizontal => Offset(-offset.pixels, 0.0), - Axis.vertical => Offset(0.0, -offset.pixels), - }; + Axis.horizontal => Offset(-offset.pixels, 0.0), + Axis.vertical => Offset(0.0, -offset.pixels), + }; double get _viewportExtent { assert(hasSize); @@ -1792,12 +1797,14 @@ class RenderEditable extends RenderBox Offset(0.0, preferredLineHeight) + caretOffset + paintOffset; return [TextSelectionPoint(start, null)]; } else { - final Offset start = Offset( + final Offset start = + Offset( clampDouble(boxes.first.start, 0, _textPainter.size.width), boxes.first.bottom, ) + paintOffset; - final Offset end = Offset( + final Offset end = + Offset( clampDouble(boxes.last.end, 0, _textPainter.size.width), boxes.last.bottom, ) + @@ -1925,11 +1932,11 @@ class RenderEditable extends RenderBox double computeMinIntrinsicWidth(double height) { final List placeholderDimensions = layoutInlineChildren( - double.infinity, - (RenderBox child, BoxConstraints constraints) => - Size(child.getMinIntrinsicWidth(double.infinity), 0.0), - ChildLayoutHelper.getDryBaseline, - ); + double.infinity, + (RenderBox child, BoxConstraints constraints) => + Size(child.getMinIntrinsicWidth(double.infinity), 0.0), + ChildLayoutHelper.getDryBaseline, + ); final (double minWidth, double maxWidth) = _adjustConstraints(); return (_textIntrinsics ..setPlaceholderDimensions(placeholderDimensions) @@ -1939,8 +1946,8 @@ class RenderEditable extends RenderBox @override double computeMaxIntrinsicWidth(double height) { - final List placeholderDimensions = - layoutInlineChildren( + final List + placeholderDimensions = layoutInlineChildren( double.infinity, // Height and baseline is irrelevant as all text will be laid // out in a single line. Therefore, using 0.0 as a dummy for the height. @@ -1996,9 +2003,9 @@ class RenderEditable extends RenderBox final (double minWidth, double maxWidth) = _adjustConstraints( maxWidth: width, ); - estimatedHeight = (_textIntrinsics - ..layout(minWidth: minWidth, maxWidth: maxWidth)) - .height; + estimatedHeight = + (_textIntrinsics..layout(minWidth: minWidth, maxWidth: maxWidth)) + .height; } return math.max(estimatedHeight, minHeight); } @@ -2067,7 +2074,8 @@ class RenderEditable extends RenderBox // text justification, as graphemeClusterLayoutBounds.width is the advance // width to the next character, so there's no gap between their // graphemeClusterLayoutBounds rects. - final InlineSpan? spanHit = glyph != null && + final InlineSpan? spanHit = + glyph != null && glyph.graphemeClusterLayoutBounds.contains(effectivePosition) ? _textPainter.text!.getSpanForPosition( TextPosition(offset: glyph.graphemeClusterCodeUnitRange.start), @@ -2264,15 +2272,18 @@ class RenderEditable extends RenderBox : _textPainter.getPositionForOffset( globalToLocal(to) - _paintOffset, ); - final TextSelection toWord = - toPosition == fromPosition ? fromWord : getWordAtOffset(toPosition); + final TextSelection toWord = toPosition == fromPosition + ? fromWord + : getWordAtOffset(toPosition); final bool isFromWordBeforeToWord = fromWord.start < toWord.end; // bggRGjQaUbCoE longpress - var startOffset = - isFromWordBeforeToWord ? fromWord.baseOffset : toWord.baseOffset; - var endOffset = - isFromWordBeforeToWord ? toWord.extentOffset : fromWord.extentOffset; + var startOffset = isFromWordBeforeToWord + ? fromWord.baseOffset + : toWord.baseOffset; + var endOffset = isFromWordBeforeToWord + ? toWord.extentOffset + : fromWord.extentOffset; final newOffset = controller.longPressOffset(startOffset, endOffset); startOffset = newOffset.startOffset; endOffset = newOffset.endOffset; @@ -2479,11 +2490,11 @@ class RenderEditable extends RenderBox return Offset( globalOffset.dx.isFinite ? (globalOffset.dx / pixelMultiple).round() * pixelMultiple - - globalOffset.dx + globalOffset.dx : 0, globalOffset.dy.isFinite ? (globalOffset.dy / pixelMultiple).round() * pixelMultiple - - globalOffset.dy + globalOffset.dy : 0, ); } @@ -2560,15 +2571,15 @@ class RenderEditable extends RenderBox assert(maxLines != 1 || _textPainter.maxLines == 1); final double preferredHeight = switch (maxLines) { null => math.max( - _textPainter.height, - preferredLineHeight * (minLines ?? 0), - ), + _textPainter.height, + preferredLineHeight * (minLines ?? 0), + ), 1 => _textPainter.height, final int maxLines => clampDouble( - _textPainter.height, - preferredLineHeight * (minLines ?? maxLines), - preferredLineHeight * maxLines, - ), + _textPainter.height, + preferredLineHeight * (minLines ?? maxLines), + preferredLineHeight * maxLines, + ), }; size = Size(width, constraints.constrainHeight(preferredHeight)); @@ -2628,11 +2639,13 @@ class RenderEditable extends RenderBox }) { Offset deltaPosition = Offset.zero; final double topBound = -floatingCursorAddedMargin.top; - final double bottomBound = math.min(size.height, _textPainter.height) - + final double bottomBound = + math.min(size.height, _textPainter.height) - preferredLineHeight + floatingCursorAddedMargin.bottom; final double leftBound = -floatingCursorAddedMargin.left; - final double rightBound = math.min(size.width, _textPainter.width) + + final double rightBound = + math.min(size.width, _textPainter.width) + floatingCursorAddedMargin.right; final Rect boundingRects = Rect.fromLTRB( leftBound, @@ -2739,8 +2752,9 @@ class RenderEditable extends RenderBox animationValue, )! : _kFloatingCursorSizeIncrease; - _caretPainter.floatingCursorRect = - sizeAdjustment.inflateRect(_caretPrototype).shift(boundedOffset); + _caretPainter.floatingCursorRect = sizeAdjustment + .inflateRect(_caretPrototype) + .shift(boundedOffset); } else { _caretPainter.floatingCursorRect = null; } @@ -2957,8 +2971,8 @@ class RenderEditable extends RenderBox class _RenderEditableCustomPaint extends RenderBox { _RenderEditableCustomPaint({RenderEditablePainter? painter}) - : _painter = painter, - super(); + : _painter = painter, + super(); @override RenderEditable? get parent => super.parent as RenderEditable?; @@ -3070,8 +3084,8 @@ abstract class RenderEditablePainter extends ChangeNotifier { class _TextHighlightPainter extends RenderEditablePainter { _TextHighlightPainter({TextRange? highlightedRange, Color? highlightColor}) - : _highlightedRange = highlightedRange, - _highlightColor = highlightColor; + : _highlightedRange = highlightedRange, + _highlightColor = highlightColor; final Paint highlightPaint = Paint(); @@ -3139,7 +3153,10 @@ class _TextHighlightPainter extends RenderEditablePainter { for (final TextBox box in boxes) { canvas.drawRect( - box.toRect().shift(renderEditable._paintOffset).intersect( + box + .toRect() + .shift(renderEditable._paintOffset) + .intersect( Rect.fromLTWH(0, 0, textPainter.width, textPainter.height), ), highlightPaint, @@ -3282,8 +3299,8 @@ class _CaretPainter extends RenderEditablePainter { final Color? caretColor = floatingCursorRect == null ? this.caretColor : showRegularCaret - ? backgroundCursorColor - : null; + ? backgroundCursorColor + : null; final TextPosition caretTextPosition = floatingCursorRect == null ? selection.extent : renderEditable._floatingCursorTextPosition; diff --git a/lib/common/widgets/text_field/editable_text.dart b/lib/common/widgets/text_field/editable_text.dart index b4feb9731..a1951571f 100644 --- a/lib/common/widgets/text_field/editable_text.dart +++ b/lib/common/widgets/text_field/editable_text.dart @@ -55,8 +55,8 @@ export 'package:flutter/services.dart' /// Signature for the callback that reports when the user changes the selection /// (including the cursor location). -typedef SelectionChangedCallback = void Function( - TextSelection selection, SelectionChangedCause? cause); +typedef SelectionChangedCallback = + void Function(TextSelection selection, SelectionChangedCause? cause); /// Signature for a widget builder that builds a context menu for the given /// [EditableTextState]. @@ -65,13 +65,13 @@ typedef SelectionChangedCallback = void Function( /// /// * [SelectableRegionContextMenuBuilder], which performs the same role for /// [SelectableRegion]. -typedef EditableTextContextMenuBuilder = Widget Function( - BuildContext context, EditableTextState editableTextState); +typedef EditableTextContextMenuBuilder = + Widget Function(BuildContext context, EditableTextState editableTextState); // Signature for a function that determines the target location of the given // [TextPosition] after applying the given [TextBoundary]. -typedef _ApplyTextBoundary = TextPosition Function( - TextPosition, bool, TextBoundary); +typedef _ApplyTextBoundary = + TextPosition Function(TextPosition, bool, TextBoundary); // The time it takes for the cursor to fade from fully opaque to fully // transparent and vice versa. A full cursor blink, from transparent to opaque @@ -83,8 +83,11 @@ const Duration _kCursorBlinkHalfPeriod = Duration(milliseconds: 500); const int _kObscureShowLatestCharCursorTicks = 3; class _CompositionCallback extends SingleChildRenderObjectWidget { - const _CompositionCallback( - {required this.compositeCallback, required this.enabled, super.child}); + const _CompositionCallback({ + required this.compositeCallback, + required this.enabled, + super.child, + }); final CompositionCallback compositeCallback; final bool enabled; @@ -95,7 +98,9 @@ class _CompositionCallback extends SingleChildRenderObjectWidget { @override void updateRenderObject( - BuildContext context, _RenderCompositionCallback renderObject) { + BuildContext context, + _RenderCompositionCallback renderObject, + ) { super.updateRenderObject(context, renderObject); // _EditableTextState always uses the same callback. assert(renderObject.compositeCallback == compositeCallback); @@ -203,18 +208,18 @@ class _KeyFrame { class _DiscreteKeyFrameSimulation extends Simulation { _DiscreteKeyFrameSimulation.iOSBlinkingCaret() - : this._(_KeyFrame.iOSBlinkingCaretKeyFrames, 1); + : this._(_KeyFrame.iOSBlinkingCaretKeyFrames, 1); _DiscreteKeyFrameSimulation._(this._keyFrames, this.maxDuration) - : assert(_keyFrames.isNotEmpty), - assert(_keyFrames.last.time <= maxDuration), - assert(() { - for (int i = 0; i < _keyFrames.length - 1; i += 1) { - if (_keyFrames[i].time > _keyFrames[i + 1].time) { - return false; - } + : assert(_keyFrames.isNotEmpty), + assert(_keyFrames.last.time <= maxDuration), + assert(() { + for (int i = 0; i < _keyFrames.length - 1; i += 1) { + if (_keyFrames[i].time > _keyFrames[i + 1].time) { + return false; } - return true; - }(), 'The key frame sequence must be sorted by time.'); + } + return true; + }(), 'The key frame sequence must be sorted by time.'); final double maxDuration; @@ -582,64 +587,68 @@ class EditableText extends StatefulWidget { this.spellCheckConfiguration, this.magnifierConfiguration = TextMagnifierConfiguration.disabled, this.undoController, - }) : assert(obscuringCharacter.length == 1), - smartDashesType = smartDashesType ?? - (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), - smartQuotesType = smartQuotesType ?? - (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), - assert(minLines == null || minLines > 0), - assert( - (maxLines == null) || (minLines == null) || (maxLines >= minLines), - "minLines can't be greater than maxLines", - ), - assert( - !expands || (maxLines == null && minLines == null), - 'minLines and maxLines must be null when expands is true.', - ), - assert(!obscureText || maxLines == 1, - 'Obscured fields cannot be multiline.'), - enableInteractiveSelection = - enableInteractiveSelection ?? (!readOnly || !obscureText), - toolbarOptions = selectionControls is TextSelectionHandleControls && - toolbarOptions == null - ? ToolbarOptions.empty - : toolbarOptions ?? - (obscureText - ? (readOnly - // No point in even offering "Select All" in a read-only obscured - // field. - ? ToolbarOptions.empty - // Writable, but obscured. - : const ToolbarOptions(selectAll: true, paste: true)) - : (readOnly - // Read-only, not obscured. - ? const ToolbarOptions(selectAll: true, copy: true) - // Writable, not obscured. - : const ToolbarOptions( - copy: true, - cut: true, - selectAll: true, - paste: true, - ))), - assert( - spellCheckConfiguration == null || - spellCheckConfiguration == - const SpellCheckConfiguration.disabled() || - spellCheckConfiguration.misspelledTextStyle != null, - 'spellCheckConfiguration must specify a misspelledTextStyle if spell check behavior is desired', - ), - _strutStyle = strutStyle, - keyboardType = keyboardType ?? - _inferKeyboardType( - autofillHints: autofillHints, maxLines: maxLines), - inputFormatters = maxLines == 1 - ? [ - FilteringTextInputFormatter.singleLineFormatter, - ...inputFormatters ?? - const Iterable.empty(), - ] - : inputFormatters, - showCursor = showCursor ?? !readOnly; + }) : assert(obscuringCharacter.length == 1), + smartDashesType = + smartDashesType ?? + (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), + smartQuotesType = + smartQuotesType ?? + (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), + assert(minLines == null || minLines > 0), + assert( + (maxLines == null) || (minLines == null) || (maxLines >= minLines), + "minLines can't be greater than maxLines", + ), + assert( + !expands || (maxLines == null && minLines == null), + 'minLines and maxLines must be null when expands is true.', + ), + assert( + !obscureText || maxLines == 1, + 'Obscured fields cannot be multiline.', + ), + enableInteractiveSelection = + enableInteractiveSelection ?? (!readOnly || !obscureText), + toolbarOptions = + selectionControls is TextSelectionHandleControls && + toolbarOptions == null + ? ToolbarOptions.empty + : toolbarOptions ?? + (obscureText + ? (readOnly + // No point in even offering "Select All" in a read-only obscured + // field. + ? ToolbarOptions.empty + // Writable, but obscured. + : const ToolbarOptions(selectAll: true, paste: true)) + : (readOnly + // Read-only, not obscured. + ? const ToolbarOptions(selectAll: true, copy: true) + // Writable, not obscured. + : const ToolbarOptions( + copy: true, + cut: true, + selectAll: true, + paste: true, + ))), + assert( + spellCheckConfiguration == null || + spellCheckConfiguration == + const SpellCheckConfiguration.disabled() || + spellCheckConfiguration.misspelledTextStyle != null, + 'spellCheckConfiguration must specify a misspelledTextStyle if spell check behavior is desired', + ), + _strutStyle = strutStyle, + keyboardType = + keyboardType ?? + _inferKeyboardType(autofillHints: autofillHints, maxLines: maxLines), + inputFormatters = maxLines == 1 + ? [ + FilteringTextInputFormatter.singleLineFormatter, + ...inputFormatters ?? const Iterable.empty(), + ] + : inputFormatters, + showCursor = showCursor ?? !readOnly; /// Controls the text being edited. final RichTextEditingController controller; @@ -1761,28 +1770,44 @@ class EditableText extends StatefulWidget { resultButtonItem.addAll([ if (onCut != null) ContextMenuButtonItem( - onPressed: onCut, type: ContextMenuButtonType.cut), + onPressed: onCut, + type: ContextMenuButtonType.cut, + ), if (onCopy != null) ContextMenuButtonItem( - onPressed: onCopy, type: ContextMenuButtonType.copy), + onPressed: onCopy, + type: ContextMenuButtonType.copy, + ), if (onPaste != null) ContextMenuButtonItem( - onPressed: onPaste, type: ContextMenuButtonType.paste), + onPressed: onPaste, + type: ContextMenuButtonType.paste, + ), if (onShare != null && showShareBeforeSelectAll) ContextMenuButtonItem( - onPressed: onShare, type: ContextMenuButtonType.share), + onPressed: onShare, + type: ContextMenuButtonType.share, + ), if (onSelectAll != null) ContextMenuButtonItem( - onPressed: onSelectAll, type: ContextMenuButtonType.selectAll), + onPressed: onSelectAll, + type: ContextMenuButtonType.selectAll, + ), if (onLookUp != null) ContextMenuButtonItem( - onPressed: onLookUp, type: ContextMenuButtonType.lookUp), + onPressed: onLookUp, + type: ContextMenuButtonType.lookUp, + ), if (onSearchWeb != null) ContextMenuButtonItem( - onPressed: onSearchWeb, type: ContextMenuButtonType.searchWeb), + onPressed: onSearchWeb, + type: ContextMenuButtonType.searchWeb, + ), if (onShare != null && !showShareBeforeSelectAll) ContextMenuButtonItem( - onPressed: onShare, type: ContextMenuButtonType.share), + onPressed: onShare, + type: ContextMenuButtonType.share, + ), ]); } @@ -1822,8 +1847,8 @@ class EditableText extends StatefulWidget { switch (defaultTargetPlatform) { case TargetPlatform.iOS: case TargetPlatform.macOS: - const Map iOSKeyboardType = - { + const Map + iOSKeyboardType = { AutofillHints.addressCity: TextInputType.name, AutofillHints.addressCityAndState: TextInputType.name, // Autofill not working. @@ -1880,74 +1905,75 @@ class EditableText extends StatefulWidget { const Map inferKeyboardType = { - AutofillHints.addressCity: TextInputType.streetAddress, - AutofillHints.addressCityAndState: TextInputType.streetAddress, - AutofillHints.addressState: TextInputType.streetAddress, - AutofillHints.birthday: TextInputType.datetime, - AutofillHints.birthdayDay: TextInputType.datetime, - AutofillHints.birthdayMonth: TextInputType.datetime, - AutofillHints.birthdayYear: TextInputType.datetime, - AutofillHints.countryCode: TextInputType.number, - AutofillHints.countryName: TextInputType.text, - AutofillHints.creditCardExpirationDate: TextInputType.datetime, - AutofillHints.creditCardExpirationDay: TextInputType.datetime, - AutofillHints.creditCardExpirationMonth: TextInputType.datetime, - AutofillHints.creditCardExpirationYear: TextInputType.datetime, - AutofillHints.creditCardFamilyName: TextInputType.name, - AutofillHints.creditCardGivenName: TextInputType.name, - AutofillHints.creditCardMiddleName: TextInputType.name, - AutofillHints.creditCardName: TextInputType.name, - AutofillHints.creditCardNumber: TextInputType.number, - AutofillHints.creditCardSecurityCode: TextInputType.number, - AutofillHints.creditCardType: TextInputType.text, - AutofillHints.email: TextInputType.emailAddress, - AutofillHints.familyName: TextInputType.name, - AutofillHints.fullStreetAddress: TextInputType.streetAddress, - AutofillHints.gender: TextInputType.text, - AutofillHints.givenName: TextInputType.name, - AutofillHints.impp: TextInputType.url, - AutofillHints.jobTitle: TextInputType.text, - AutofillHints.language: TextInputType.text, - AutofillHints.location: TextInputType.streetAddress, - AutofillHints.middleInitial: TextInputType.name, - AutofillHints.middleName: TextInputType.name, - AutofillHints.name: TextInputType.name, - AutofillHints.namePrefix: TextInputType.name, - AutofillHints.nameSuffix: TextInputType.name, - AutofillHints.newPassword: TextInputType.text, - AutofillHints.newUsername: TextInputType.text, - AutofillHints.nickname: TextInputType.text, - AutofillHints.oneTimeCode: TextInputType.text, - AutofillHints.organizationName: TextInputType.text, - AutofillHints.password: TextInputType.text, - AutofillHints.photo: TextInputType.text, - AutofillHints.postalAddress: TextInputType.streetAddress, - AutofillHints.postalAddressExtended: TextInputType.streetAddress, - AutofillHints.postalAddressExtendedPostalCode: TextInputType.number, - AutofillHints.postalCode: TextInputType.number, - AutofillHints.streetAddressLevel1: TextInputType.streetAddress, - AutofillHints.streetAddressLevel2: TextInputType.streetAddress, - AutofillHints.streetAddressLevel3: TextInputType.streetAddress, - AutofillHints.streetAddressLevel4: TextInputType.streetAddress, - AutofillHints.streetAddressLine1: TextInputType.streetAddress, - AutofillHints.streetAddressLine2: TextInputType.streetAddress, - AutofillHints.streetAddressLine3: TextInputType.streetAddress, - AutofillHints.sublocality: TextInputType.streetAddress, - AutofillHints.telephoneNumber: TextInputType.phone, - AutofillHints.telephoneNumberAreaCode: TextInputType.phone, - AutofillHints.telephoneNumberCountryCode: TextInputType.phone, - AutofillHints.telephoneNumberDevice: TextInputType.phone, - AutofillHints.telephoneNumberExtension: TextInputType.phone, - AutofillHints.telephoneNumberLocal: TextInputType.phone, - AutofillHints.telephoneNumberLocalPrefix: TextInputType.phone, - AutofillHints.telephoneNumberLocalSuffix: TextInputType.phone, - AutofillHints.telephoneNumberNational: TextInputType.phone, - AutofillHints.transactionAmount: - TextInputType.numberWithOptions(decimal: true), - AutofillHints.transactionCurrency: TextInputType.text, - AutofillHints.url: TextInputType.url, - AutofillHints.username: TextInputType.text, - }; + AutofillHints.addressCity: TextInputType.streetAddress, + AutofillHints.addressCityAndState: TextInputType.streetAddress, + AutofillHints.addressState: TextInputType.streetAddress, + AutofillHints.birthday: TextInputType.datetime, + AutofillHints.birthdayDay: TextInputType.datetime, + AutofillHints.birthdayMonth: TextInputType.datetime, + AutofillHints.birthdayYear: TextInputType.datetime, + AutofillHints.countryCode: TextInputType.number, + AutofillHints.countryName: TextInputType.text, + AutofillHints.creditCardExpirationDate: TextInputType.datetime, + AutofillHints.creditCardExpirationDay: TextInputType.datetime, + AutofillHints.creditCardExpirationMonth: TextInputType.datetime, + AutofillHints.creditCardExpirationYear: TextInputType.datetime, + AutofillHints.creditCardFamilyName: TextInputType.name, + AutofillHints.creditCardGivenName: TextInputType.name, + AutofillHints.creditCardMiddleName: TextInputType.name, + AutofillHints.creditCardName: TextInputType.name, + AutofillHints.creditCardNumber: TextInputType.number, + AutofillHints.creditCardSecurityCode: TextInputType.number, + AutofillHints.creditCardType: TextInputType.text, + AutofillHints.email: TextInputType.emailAddress, + AutofillHints.familyName: TextInputType.name, + AutofillHints.fullStreetAddress: TextInputType.streetAddress, + AutofillHints.gender: TextInputType.text, + AutofillHints.givenName: TextInputType.name, + AutofillHints.impp: TextInputType.url, + AutofillHints.jobTitle: TextInputType.text, + AutofillHints.language: TextInputType.text, + AutofillHints.location: TextInputType.streetAddress, + AutofillHints.middleInitial: TextInputType.name, + AutofillHints.middleName: TextInputType.name, + AutofillHints.name: TextInputType.name, + AutofillHints.namePrefix: TextInputType.name, + AutofillHints.nameSuffix: TextInputType.name, + AutofillHints.newPassword: TextInputType.text, + AutofillHints.newUsername: TextInputType.text, + AutofillHints.nickname: TextInputType.text, + AutofillHints.oneTimeCode: TextInputType.text, + AutofillHints.organizationName: TextInputType.text, + AutofillHints.password: TextInputType.text, + AutofillHints.photo: TextInputType.text, + AutofillHints.postalAddress: TextInputType.streetAddress, + AutofillHints.postalAddressExtended: TextInputType.streetAddress, + AutofillHints.postalAddressExtendedPostalCode: TextInputType.number, + AutofillHints.postalCode: TextInputType.number, + AutofillHints.streetAddressLevel1: TextInputType.streetAddress, + AutofillHints.streetAddressLevel2: TextInputType.streetAddress, + AutofillHints.streetAddressLevel3: TextInputType.streetAddress, + AutofillHints.streetAddressLevel4: TextInputType.streetAddress, + AutofillHints.streetAddressLine1: TextInputType.streetAddress, + AutofillHints.streetAddressLine2: TextInputType.streetAddress, + AutofillHints.streetAddressLine3: TextInputType.streetAddress, + AutofillHints.sublocality: TextInputType.streetAddress, + AutofillHints.telephoneNumber: TextInputType.phone, + AutofillHints.telephoneNumberAreaCode: TextInputType.phone, + AutofillHints.telephoneNumberCountryCode: TextInputType.phone, + AutofillHints.telephoneNumberDevice: TextInputType.phone, + AutofillHints.telephoneNumberExtension: TextInputType.phone, + AutofillHints.telephoneNumberLocal: TextInputType.phone, + AutofillHints.telephoneNumberLocalPrefix: TextInputType.phone, + AutofillHints.telephoneNumberLocalSuffix: TextInputType.phone, + AutofillHints.telephoneNumberNational: TextInputType.phone, + AutofillHints.transactionAmount: TextInputType.numberWithOptions( + decimal: true, + ), + AutofillHints.transactionCurrency: TextInputType.text, + AutofillHints.url: TextInputType.url, + AutofillHints.username: TextInputType.text, + }; return inferKeyboardType[effectiveHint] ?? TextInputType.text; } @@ -1958,53 +1984,83 @@ class EditableText extends StatefulWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty( - 'controller', controller)); - properties.add(DiagnosticsProperty('focusNode', focusNode)); - properties.add(DiagnosticsProperty('obscureText', obscureText, - defaultValue: false)); properties.add( - DiagnosticsProperty('readOnly', readOnly, defaultValue: false)); - properties.add(DiagnosticsProperty('autocorrect', autocorrect, - defaultValue: true)); + DiagnosticsProperty('controller', controller), + ); + properties.add(DiagnosticsProperty('focusNode', focusNode)); + properties.add( + DiagnosticsProperty( + 'obscureText', + obscureText, + defaultValue: false, + ), + ); + properties.add( + DiagnosticsProperty('readOnly', readOnly, defaultValue: false), + ); + properties.add( + DiagnosticsProperty('autocorrect', autocorrect, defaultValue: true), + ); properties.add( EnumProperty( 'smartDashesType', smartDashesType, - defaultValue: - obscureText ? SmartDashesType.disabled : SmartDashesType.enabled, + defaultValue: obscureText + ? SmartDashesType.disabled + : SmartDashesType.enabled, ), ); properties.add( EnumProperty( 'smartQuotesType', smartQuotesType, - defaultValue: - obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled, + defaultValue: obscureText + ? SmartQuotesType.disabled + : SmartQuotesType.enabled, ), ); properties.add( - DiagnosticsProperty('enableSuggestions', enableSuggestions, - defaultValue: true), + DiagnosticsProperty( + 'enableSuggestions', + enableSuggestions, + defaultValue: true, + ), ); style.debugFillProperties(properties); properties.add( - EnumProperty('textAlign', textAlign, defaultValue: null)); - properties.add(EnumProperty('textDirection', textDirection, - defaultValue: null)); - properties - .add(DiagnosticsProperty('locale', locale, defaultValue: null)); - properties.add(DiagnosticsProperty('textScaler', textScaler, - defaultValue: null)); + EnumProperty('textAlign', textAlign, defaultValue: null), + ); + properties.add( + EnumProperty( + 'textDirection', + textDirection, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty('locale', locale, defaultValue: null), + ); + properties.add( + DiagnosticsProperty( + 'textScaler', + textScaler, + defaultValue: null, + ), + ); properties.add(IntProperty('maxLines', maxLines, defaultValue: 1)); properties.add(IntProperty('minLines', minLines, defaultValue: null)); properties.add( - DiagnosticsProperty('expands', expands, defaultValue: false)); + DiagnosticsProperty('expands', expands, defaultValue: false), + ); properties.add( - DiagnosticsProperty('autofocus', autofocus, defaultValue: false)); + DiagnosticsProperty('autofocus', autofocus, defaultValue: false), + ); properties.add( - DiagnosticsProperty('keyboardType', keyboardType, - defaultValue: null), + DiagnosticsProperty( + 'keyboardType', + keyboardType, + defaultValue: null, + ), ); properties.add( DiagnosticsProperty( @@ -2014,12 +2070,18 @@ class EditableText extends StatefulWidget { ), ); properties.add( - DiagnosticsProperty('scrollPhysics', scrollPhysics, - defaultValue: null), + DiagnosticsProperty( + 'scrollPhysics', + scrollPhysics, + defaultValue: null, + ), ); properties.add( - DiagnosticsProperty>('autofillHints', autofillHints, - defaultValue: null), + DiagnosticsProperty>( + 'autofillHints', + autofillHints, + defaultValue: null, + ), ); properties.add( DiagnosticsProperty( @@ -2029,8 +2091,11 @@ class EditableText extends StatefulWidget { ), ); properties.add( - DiagnosticsProperty('scribbleEnabled', scribbleEnabled, - defaultValue: true), + DiagnosticsProperty( + 'scribbleEnabled', + scribbleEnabled, + defaultValue: true, + ), ); properties.add( DiagnosticsProperty( @@ -2091,16 +2156,18 @@ class EditableTextState extends State implements AutofillClient { Timer? _cursorTimer; AnimationController get _cursorBlinkOpacityController { - return _backingCursorBlinkOpacityController ??= - AnimationController(vsync: this)..addListener(_onCursorColorTick); + return _backingCursorBlinkOpacityController ??= AnimationController( + vsync: this, + )..addListener(_onCursorColorTick); } AnimationController? _backingCursorBlinkOpacityController; late final Simulation _iosBlinkCursorSimulation = _DiscreteKeyFrameSimulation.iOSBlinkingCaret(); - final ValueNotifier _cursorVisibilityNotifier = - ValueNotifier(true); + final ValueNotifier _cursorVisibilityNotifier = ValueNotifier( + true, + ); final GlobalKey _editableKey = GlobalKey(); /// Detects whether the clipboard can paste. @@ -2116,18 +2183,17 @@ class EditableTextState extends State /// /// See also: /// * [LiveText], where the availability of Live Text input can be obtained. - final LiveTextInputStatusNotifier? _liveTextInputStatus = - kIsWeb ? null : LiveTextInputStatusNotifier(); + final LiveTextInputStatusNotifier? _liveTextInputStatus = kIsWeb + ? null + : LiveTextInputStatusNotifier(); TextInputConnection? _textInputConnection; bool get _hasInputConnection => _textInputConnection?.attached ?? false; TextSelectionOverlay? _selectionOverlay; ScrollNotificationObserverState? _scrollNotificationObserver; - ({ - TextEditingValue value, - Rect selectionBounds - })? _dataWhenToolbarShowScheduled; + ({TextEditingValue value, Rect selectionBounds})? + _dataWhenToolbarShowScheduled; bool _listeningToScrollNotificationObserver = false; bool get _webContextMenuEnabled => kIsWeb && BrowserContextMenu.enabled; @@ -2397,7 +2463,8 @@ class EditableTextState extends State TextEditingValue( text: textEditingValue.text, selection: TextSelection.collapsed( - offset: textEditingValue.selection.end), + offset: textEditingValue.selection.end, + ), ), SelectionChangedCause.toolbar, ); @@ -2458,8 +2525,10 @@ class EditableTextState extends State // After the paste, the cursor should be collapsed and located after the // pasted content. final TextSelection selection = textEditingValue.selection; - final int lastSelectionIndex = - math.max(selection.baseOffset, selection.extentOffset); + final int lastSelectionIndex = math.max( + selection.baseOffset, + selection.extentOffset, + ); // final TextEditingValue collapsedTextEditingValue = // textEditingValue.copyWith( // selection: TextSelection.collapsed(offset: lastSelectionIndex), @@ -2514,7 +2583,9 @@ class EditableTextState extends State userUpdateTextEditingValue( textEditingValue.copyWith( selection: TextSelection( - baseOffset: 0, extentOffset: textEditingValue.text.length), + baseOffset: 0, + extentOffset: textEditingValue.text.length, + ), ), cause, ); @@ -2552,8 +2623,9 @@ class EditableTextState extends State Future lookUpSelection(SelectionChangedCause cause) async { assert(!widget.obscureText); - final String text = - textEditingValue.selection.textInside(textEditingValue.text); + final String text = textEditingValue.selection.textInside( + textEditingValue.text, + ); if (widget.obscureText || text.isEmpty) { return; } @@ -2573,8 +2645,9 @@ class EditableTextState extends State return; } - final String text = - textEditingValue.selection.textInside(textEditingValue.text); + final String text = textEditingValue.selection.textInside( + textEditingValue.text, + ); if (text.isNotEmpty) { await SystemChannels.platform.invokeMethod('SearchWeb.invoke', text); } @@ -2593,8 +2666,9 @@ class EditableTextState extends State return; } - final String text = - textEditingValue.selection.textInside(textEditingValue.text); + final String text = textEditingValue.selection.textInside( + textEditingValue.text, + ); if (text.isNotEmpty) { await SystemChannels.platform.invokeMethod('Share.invoke', text); } @@ -2659,11 +2733,15 @@ class EditableTextState extends State ) { final SpellCheckService? spellCheckService = configuration?.spellCheckService; - final bool spellCheckAutomaticallyDisabled = configuration == null || + final bool spellCheckAutomaticallyDisabled = + configuration == null || configuration == const SpellCheckConfiguration.disabled(); - final bool spellCheckServiceIsConfigured = spellCheckService != null || + final bool spellCheckServiceIsConfigured = + spellCheckService != null || WidgetsBinding - .instance.platformDispatcher.nativeSpellCheckServiceDefined; + .instance + .platformDispatcher + .nativeSpellCheckServiceDefined; if (spellCheckAutomaticallyDisabled || !spellCheckServiceIsConfigured) { // Only enable spell check if a non-disabled configuration is provided // and if that configuration does not specify a spell check service, @@ -2700,8 +2778,9 @@ class EditableTextState extends State 'Use `contextMenuBuilder` instead of `toolbarOptions`. ' 'This feature was deprecated after v3.3.0-0.5.pre.', ) - List? buttonItemsForToolbarOptions( - [TargetPlatform? targetPlatform]) { + List? buttonItemsForToolbarOptions([ + TargetPlatform? targetPlatform, + ]) { final ToolbarOptions toolbarOptions = widget.toolbarOptions; if (toolbarOptions == ToolbarOptions.empty) { return null; @@ -2770,15 +2849,17 @@ class EditableTextState extends State selectedGraphemes.characters.first.length; final Rect? startCharacterRect = renderEditable.getRectForComposingRange( TextRange( - start: selection.start, - end: selection.start + firstSelectedGraphemeExtent), + start: selection.start, + end: selection.start + firstSelectedGraphemeExtent, + ), ); final int lastSelectedGraphemeExtent = selectedGraphemes.characters.last.length; final Rect? endCharacterRect = renderEditable.getRectForComposingRange( TextRange( - start: selection.end - lastSelectedGraphemeExtent, - end: selection.end), + start: selection.end - lastSelectedGraphemeExtent, + end: selection.end, + ), ); return ( startGlyphHeight: @@ -2805,11 +2886,11 @@ class EditableTextState extends State final ( startGlyphHeight: double startGlyphHeight, - endGlyphHeight: double endGlyphHeight + endGlyphHeight: double endGlyphHeight, ) = getGlyphHeights(); final TextSelection selection = textEditingValue.selection; - final List points = - renderEditable.getEndpointsForSelection(selection); + final List points = renderEditable + .getEndpointsForSelection(selection); return TextSelectionToolbarAnchors.fromSelection( renderBox: renderEditable, startGlyphHeight: startGlyphHeight, @@ -2838,33 +2919,33 @@ class EditableTextState extends State /// button Widgets for the current platform given [ContextMenuButtonItem]s. List get contextMenuButtonItems { return buttonItemsForToolbarOptions() ?? - EditableText.getEditableButtonItems( - clipboardStatus: clipboardStatus.value, - onCopy: copyEnabled - ? () => copySelection(SelectionChangedCause.toolbar) - : null, - onCut: cutEnabled - ? () => cutSelection(SelectionChangedCause.toolbar) - : null, - onPaste: pasteEnabled - ? () => pasteText(SelectionChangedCause.toolbar) - : null, - onSelectAll: selectAllEnabled - ? () => selectAll(SelectionChangedCause.toolbar) - : null, - onLookUp: lookUpEnabled - ? () => lookUpSelection(SelectionChangedCause.toolbar) - : null, - onSearchWeb: searchWebEnabled - ? () => searchWebForSelection(SelectionChangedCause.toolbar) - : null, - onShare: shareEnabled - ? () => shareSelection(SelectionChangedCause.toolbar) - : null, - onLiveTextInput: liveTextInputEnabled - ? () => _startLiveTextInput(SelectionChangedCause.toolbar) - : null, - ) + EditableText.getEditableButtonItems( + clipboardStatus: clipboardStatus.value, + onCopy: copyEnabled + ? () => copySelection(SelectionChangedCause.toolbar) + : null, + onCut: cutEnabled + ? () => cutSelection(SelectionChangedCause.toolbar) + : null, + onPaste: pasteEnabled + ? () => pasteText(SelectionChangedCause.toolbar) + : null, + onSelectAll: selectAllEnabled + ? () => selectAll(SelectionChangedCause.toolbar) + : null, + onLookUp: lookUpEnabled + ? () => lookUpSelection(SelectionChangedCause.toolbar) + : null, + onSearchWeb: searchWebEnabled + ? () => searchWebForSelection(SelectionChangedCause.toolbar) + : null, + onShare: shareEnabled + ? () => shareSelection(SelectionChangedCause.toolbar) + : null, + onLiveTextInput: liveTextInputEnabled + ? () => _startLiveTextInput(SelectionChangedCause.toolbar) + : null, + ) ..addAll(_textProcessingActionButtonItems); } @@ -2880,15 +2961,16 @@ class EditableTextState extends State ContextMenuButtonItem( label: action.label, onPressed: () async { - final String selectedText = - selection.textInside(textEditingValue.text); + final String selectedText = selection.textInside( + textEditingValue.text, + ); if (selectedText.isNotEmpty) { - final String? processedText = - await _processTextService.processTextAction( - action.id, - selectedText, - widget.readOnly, - ); + final String? processedText = await _processTextService + .processTextAction( + action.id, + selectedText, + widget.readOnly, + ); // If an activity does not return a modified version, just hide the toolbar. // Otherwise use the result to replace the selected text. if (processedText != null && _allowPaste) { @@ -2915,10 +2997,12 @@ class EditableTextState extends State widget.controller.addListener(_didChangeTextEditingValue); widget.focusNode.addListener(_handleFocusChanged); _cursorVisibilityNotifier.value = widget.showCursor; - _spellCheckConfiguration = - _inferSpellCheckConfiguration(widget.spellCheckConfiguration); - _appLifecycleListener = - AppLifecycleListener(onResume: () => _justResumed = true); + _spellCheckConfiguration = _inferSpellCheckConfiguration( + widget.spellCheckConfiguration, + ); + _appLifecycleListener = AppLifecycleListener( + onResume: () => _justResumed = true, + ); _initProcessTextActions(); } @@ -2974,8 +3058,9 @@ class EditableTextState extends State if (_hasInputConnection) { final int newViewId = View.of(context).viewId; if (newViewId != _viewId) { - _textInputConnection! - .updateConfig(_effectiveAutofillClient.textInputConfiguration); + _textInputConnection!.updateConfig( + _effectiveAutofillClient.textInputConfiguration, + ); } } @@ -3005,11 +3090,13 @@ class EditableTextState extends State // scroll notification observer. We only subscribe to the scroll // notification observer when the context menu is shown on platforms that // support _platformSupportsFadeOnScroll. - _scrollNotificationObserver - ?.removeListener(_handleContextMenuOnParentScroll); + _scrollNotificationObserver?.removeListener( + _handleContextMenuOnParentScroll, + ); _scrollNotificationObserver = ScrollNotificationObserver.maybeOf(context); - _scrollNotificationObserver - ?.addListener(_handleContextMenuOnParentScroll); + _scrollNotificationObserver?.addListener( + _handleContextMenuOnParentScroll, + ); } } @@ -3051,8 +3138,9 @@ class EditableTextState extends State _selectionOverlay?.handlesVisible = widget.showSelectionHandles; if (widget.autofillClient != oldWidget.autofillClient) { - _currentAutofillScope - ?.unregister(oldWidget.autofillClient?.autofillId ?? autofillId); + _currentAutofillScope?.unregister( + oldWidget.autofillClient?.autofillId ?? autofillId, + ); _currentAutofillScope?.register(_effectiveAutofillClient); } @@ -3074,16 +3162,18 @@ class EditableTextState extends State if (kIsWeb && _hasInputConnection) { if (oldWidget.readOnly != widget.readOnly) { - _textInputConnection! - .updateConfig(_effectiveAutofillClient.textInputConfiguration); + _textInputConnection!.updateConfig( + _effectiveAutofillClient.textInputConfiguration, + ); } } if (_hasInputConnection) { if (oldWidget.obscureText != widget.obscureText || oldWidget.keyboardType != widget.keyboardType) { - _textInputConnection! - .updateConfig(_effectiveAutofillClient.textInputConfiguration); + _textInputConnection!.updateConfig( + _effectiveAutofillClient.textInputConfiguration, + ); } } @@ -3109,8 +3199,8 @@ class EditableTextState extends State } final bool canPaste = widget.selectionControls is TextSelectionHandleControls - ? pasteEnabled - : widget.selectionControls?.canPaste(this) ?? false; + ? pasteEnabled + : widget.selectionControls?.canPaste(this) ?? false; if (widget.selectionEnabled && pasteEnabled && canPaste) { clipboardStatus.update(); } @@ -3119,8 +3209,9 @@ class EditableTextState extends State void _disposeScrollNotificationObserver() { _listeningToScrollNotificationObserver = false; if (_scrollNotificationObserver != null) { - _scrollNotificationObserver! - .removeListener(_handleContextMenuOnParentScroll); + _scrollNotificationObserver!.removeListener( + _handleContextMenuOnParentScroll, + ); _scrollNotificationObserver = null; } } @@ -3172,8 +3263,10 @@ class EditableTextState extends State TextEditingValue get currentTextEditingValue => _value; @override - void updateEditingValue(TextEditingValue value, - {TextEditingValue? remoteValue}) { + void updateEditingValue( + TextEditingValue value, { + TextEditingValue? remoteValue, + }) { // This method handles text editing state updates from the platform text // input plugin. The [EditableText] may not have the focus or an open input // connection, as autofill can update a disconnected [EditableText]. @@ -3186,8 +3279,9 @@ class EditableTextState extends State if (_checkNeedsAdjustAffinity(value)) { value = value.copyWith( - selection: - value.selection.copyWith(affinity: _value.selection.affinity), + selection: value.selection.copyWith( + affinity: _value.selection.affinity, + ), ); } @@ -3229,15 +3323,18 @@ class EditableTextState extends State } _currentPromptRectRange = null; - final bool revealObscuredInput = _hasInputConnection && + final bool revealObscuredInput = + _hasInputConnection && widget.obscureText && WidgetsBinding.instance.platformDispatcher.brieflyShowPassword && value.text.length == _value.text.length + 1; - _obscureShowCharTicksPending = - revealObscuredInput ? _kObscureShowLatestCharCursorTicks : 0; - _obscureLatestCharIndex = - revealObscuredInput ? _value.selection.baseOffset : null; + _obscureShowCharTicksPending = revealObscuredInput + ? _kObscureShowLatestCharCursorTicks + : 0; + _obscureLatestCharIndex = revealObscuredInput + ? _value.selection.baseOffset + : null; _formatAndSetValue(value, SelectionChangedCause.keyboard); } @@ -3322,8 +3419,9 @@ class EditableTextState extends State @override void insertContent(KeyboardInsertedContent content) { assert( - widget.contentInsertionConfiguration?.allowedMimeTypes - .contains(content.mimeType) ?? + widget.contentInsertionConfiguration?.allowedMimeTypes.contains( + content.mimeType, + ) ?? false, ); widget.contentInsertionConfiguration?.onContentInserted.call(content); @@ -3378,19 +3476,23 @@ class EditableTextState extends State offset: renderEditable.selection!.baseOffset, affinity: renderEditable.selection!.affinity, ); - startCaretCenter = - renderEditable.getLocalRectForCaret(currentTextPosition).center; + startCaretCenter = renderEditable + .getLocalRectForCaret(currentTextPosition) + .center; } _startCaretCenter = startCaretCenter; - _lastBoundedOffset = - renderEditable.calculateBoundedFloatingCursorOffset( - _startCaretCenter! - _floatingCursorOffset, - shouldResetOrigin: shouldResetOrigin, - ); + _lastBoundedOffset = renderEditable + .calculateBoundedFloatingCursorOffset( + _startCaretCenter! - _floatingCursorOffset, + shouldResetOrigin: shouldResetOrigin, + ); _lastTextPosition = currentTextPosition; renderEditable.setFloatingCursor( - point.state, _lastBoundedOffset!, _lastTextPosition!); + point.state, + _lastBoundedOffset!, + _lastTextPosition!, + ); case FloatingCursorDragState.Update: final Offset centeredPoint = point.offset! - _pointOffsetOrigin!; final Offset rawCursorOffset = @@ -3399,15 +3501,19 @@ class EditableTextState extends State _lastBoundedOffset = renderEditable .calculateBoundedFloatingCursorOffset(rawCursorOffset); _lastTextPosition = renderEditable.getPositionForPoint( - renderEditable - .localToGlobal(_lastBoundedOffset! + _floatingCursorOffset), + renderEditable.localToGlobal( + _lastBoundedOffset! + _floatingCursorOffset, + ), ); // bggRGjQaUbCoE ios single long press _lastTextPosition = widget.controller.dragOffset(_lastTextPosition!); renderEditable.setFloatingCursor( - point.state, _lastBoundedOffset!, _lastTextPosition!); + point.state, + _lastBoundedOffset!, + _lastTextPosition!, + ); case FloatingCursorDragState.End: // Resume cursor blinking. _startCursorBlink(); @@ -3426,7 +3532,7 @@ class EditableTextState extends State void _onFloatingCursorResetTick() { final Offset finalPosition = renderEditable.getLocalRectForCaret(_lastTextPosition!).centerLeft - - _floatingCursorOffset; + _floatingCursorOffset; if (_floatingCursorResetController!.isCompleted) { renderEditable.setFloatingCursor( FloatingCursorDragState.End, @@ -3462,10 +3568,16 @@ class EditableTextState extends State _lastBoundedOffset = null; } else { final double lerpValue = _floatingCursorResetController!.value; - final double lerpX = - ui.lerpDouble(_lastBoundedOffset!.dx, finalPosition.dx, lerpValue)!; - final double lerpY = - ui.lerpDouble(_lastBoundedOffset!.dy, finalPosition.dy, lerpValue)!; + final double lerpX = ui.lerpDouble( + _lastBoundedOffset!.dx, + finalPosition.dx, + lerpValue, + )!; + final double lerpY = ui.lerpDouble( + _lastBoundedOffset!.dy, + finalPosition.dy, + lerpValue, + )!; renderEditable.setFloatingCursor( FloatingCursorDragState.Update, @@ -3488,8 +3600,9 @@ class EditableTextState extends State exception: exception, stack: stack, library: 'widgets', - context: - ErrorDescription('while calling onEditingComplete for $action'), + context: ErrorDescription( + 'while calling onEditingComplete for $action', + ), ), ); } @@ -3647,7 +3760,10 @@ class EditableTextState extends State additionalOffset = expandedRect.height >= editableSize.height ? editableSize.height / 2 - expandedRect.center.dy : clampDouble( - 0.0, expandedRect.bottom - editableSize.height, expandedRect.top); + 0.0, + expandedRect.bottom - editableSize.height, + expandedRect.top, + ); unitOffset = const Offset(0, 1); } @@ -3661,13 +3777,17 @@ class EditableTextState extends State final double offsetDelta = _scrollController.offset - targetOffset; return RevealedOffset( - rect: rect.shift(unitOffset * offsetDelta), offset: targetOffset); + rect: rect.shift(unitOffset * offsetDelta), + offset: targetOffset, + ); } /// Whether to send the autofill information to the autofill service. True by /// default. bool get _needsAutofill => _effectiveAutofillClient - .textInputConfiguration.autofillConfiguration.enabled; + .textInputConfiguration + .autofillConfiguration + .enabled; // Must be called after layout. // See https://github.com/flutter/flutter/issues/126312 @@ -3687,10 +3807,14 @@ class EditableTextState extends State // notified to exclude this field from the autofill context. So we need to // provide the autofillId. _textInputConnection = _needsAutofill && currentAutofillScope != null - ? currentAutofillScope! - .attach(this, _effectiveAutofillClient.textInputConfiguration) + ? currentAutofillScope!.attach( + this, + _effectiveAutofillClient.textInputConfiguration, + ) : TextInput.attach( - this, _effectiveAutofillClient.textInputConfiguration); + this, + _effectiveAutofillClient.textInputConfiguration, + ); _updateSizeAndTransform(); _schedulePeriodicPostFrameCallbacks(); _textInputConnection! @@ -3756,10 +3880,11 @@ class EditableTextState extends State _textInputConnection = null; _lastKnownRemoteTextEditingValue = null; - final AutofillScope? currentAutofillScope = - _needsAutofill ? this.currentAutofillScope : null; - final TextInputConnection newConnection = currentAutofillScope?.attach( - this, textInputConfiguration) ?? + final AutofillScope? currentAutofillScope = _needsAutofill + ? this.currentAutofillScope + : null; + final TextInputConnection newConnection = + currentAutofillScope?.attach(this, textInputConfiguration) ?? TextInput.attach(this, _effectiveAutofillClient.textInputConfiguration); _textInputConnection = newConnection; @@ -3778,7 +3903,9 @@ class EditableTextState extends State @override void didChangeInputControl( - TextInputControl? oldControl, TextInputControl? newControl) { + TextInputControl? oldControl, + TextInputControl? newControl, + ) { if (_hasFocus && _hasInputConnection) { oldControl?.hide(); newControl?.show(); @@ -3845,18 +3972,18 @@ class EditableTextState extends State TargetPlatform.fuchsia || TargetPlatform.linux || TargetPlatform.macOS || - TargetPlatform.windows => - false, + TargetPlatform.windows => false, }; bool _isInternalScrollableNotification(BuildContext? notificationContext) { - final ScrollableState? scrollableState = - notificationContext?.findAncestorStateOfType(); + final ScrollableState? scrollableState = notificationContext + ?.findAncestorStateOfType(); return _scrollableKey.currentContext == scrollableState?.context; } bool _scrollableNotificationIsFromSameSubtree( - BuildContext? notificationContext) { + BuildContext? notificationContext, + ) { if (notificationContext == null) { return false; } @@ -3864,14 +3991,14 @@ class EditableTextState extends State // The notification context of a ScrollNotification points to the RawGestureDetector // of the Scrollable. We get the ScrollableState associated with this notification // by looking up the tree. - final ScrollableState? notificationScrollableState = - notificationContext.findAncestorStateOfType(); + final ScrollableState? notificationScrollableState = notificationContext + .findAncestorStateOfType(); if (notificationScrollableState == null) { return false; } while (currentContext != null) { - final ScrollableState? scrollableState = - currentContext.findAncestorStateOfType(); + final ScrollableState? scrollableState = currentContext + .findAncestorStateOfType(); if (scrollableState == notificationScrollableState) { return true; } @@ -3906,7 +4033,7 @@ class EditableTextState extends State final ui.FlutterView view = View.of(context); final double obscuredVertical = (view.padding.top + view.padding.bottom + view.viewInsets.bottom) / - view.devicePixelRatio; + view.devicePixelRatio; final double obscuredHorizontal = (view.padding.left + view.padding.right) / view.devicePixelRatio; final Size visibleScreenSize = Size( @@ -3941,22 +4068,28 @@ class EditableTextState extends State if (_dataWhenToolbarShowScheduled != null) { return; } - final bool toolbarIsVisible = _selectionOverlay != null && + final bool toolbarIsVisible = + _selectionOverlay != null && _selectionOverlay!.toolbarIsVisible && !_selectionOverlay!.spellCheckToolbarIsVisible; if (!toolbarIsVisible) { return; } - final List selectionBoxes = - renderEditable.getBoxesForSelection(_value.selection); - final Rect selectionBounds = _value.selection.isCollapsed || - selectionBoxes.isEmpty + final List selectionBoxes = renderEditable.getBoxesForSelection( + _value.selection, + ); + final Rect selectionBounds = + _value.selection.isCollapsed || selectionBoxes.isEmpty ? renderEditable.getLocalRectForCaret(_value.selection.extent) : selectionBoxes - .map((TextBox box) => box.toRect()) - .reduce((Rect result, Rect rect) => result.expandToInclude(rect)); - _dataWhenToolbarShowScheduled = - (value: _value, selectionBounds: selectionBounds); + .map((TextBox box) => box.toRect()) + .reduce( + (Rect result, Rect rect) => result.expandToInclude(rect), + ); + _dataWhenToolbarShowScheduled = ( + value: _value, + selectionBounds: selectionBounds, + ); _selectionOverlay?.hideToolbar(); } else if (notification is ScrollEndNotification) { if (_dataWhenToolbarShowScheduled == null) { @@ -3981,7 +4114,7 @@ class EditableTextState extends State final Rect deviceRect = _calculateDeviceRect(); final bool selectionVisibleInEditable = renderEditable.selectionStartInViewport.value || - renderEditable.selectionEndInViewport.value; + renderEditable.selectionEndInViewport.value; final Rect selectionBounds = MatrixUtils.transformRect( renderEditable.getTransformTo(null), _dataWhenToolbarShowScheduled!.selectionBounds, @@ -3992,7 +4125,8 @@ class EditableTextState extends State if (selectionVisibleInEditable && selectionOverlapsWithDeviceRect && _selectionInViewport( - _dataWhenToolbarShowScheduled!.selectionBounds)) { + _dataWhenToolbarShowScheduled!.selectionBounds, + )) { showToolbar(); _dataWhenToolbarShowScheduled = null; } @@ -4001,8 +4135,9 @@ class EditableTextState extends State } bool _selectionInViewport(Rect selectionBounds) { - RenderAbstractViewport? closestViewport = - RenderAbstractViewport.maybeOf(renderEditable); + RenderAbstractViewport? closestViewport = RenderAbstractViewport.maybeOf( + renderEditable, + ); while (closestViewport != null) { final Rect selectionBoundsLocalToViewport = MatrixUtils.transformRect( renderEditable.getTransformTo(closestViewport), @@ -4010,8 +4145,9 @@ class EditableTextState extends State ); if (selectionBoundsLocalToViewport.hasNaN || closestViewport.paintBounds.hasNaN || - !closestViewport.paintBounds - .overlaps(selectionBoundsLocalToViewport)) { + !closestViewport.paintBounds.overlaps( + selectionBoundsLocalToViewport, + )) { return false; } closestViewport = RenderAbstractViewport.maybeOf(closestViewport.parent); @@ -4049,7 +4185,9 @@ class EditableTextState extends State @pragma('vm:notify-debugger-on-exception') void _handleSelectionChanged( - TextSelection selection, SelectionChangedCause? cause) { + TextSelection selection, + SelectionChangedCause? cause, + ) { // We return early if the selection is not valid. This can happen when the // text of [EditableText] is updated at the same time as the selection is // changed by a gesture event. @@ -4100,8 +4238,9 @@ class EditableTextState extends State exception: exception, stack: stack, library: 'widgets', - context: - ErrorDescription('while calling onSelectionChanged for $cause'), + context: ErrorDescription( + 'while calling onSelectionChanged for $cause', + ), ), ); } @@ -4145,23 +4284,29 @@ class EditableTextState extends State final double handleHeight = _selectionOverlay!.selectionControls! .getHandleSize(lineHeight) .height; - final double interactiveHandleHeight = - math.max(handleHeight, kMinInteractiveDimension); - final Offset anchor = - _selectionOverlay!.selectionControls!.getHandleAnchor( - TextSelectionHandleType.collapsed, - lineHeight, + final double interactiveHandleHeight = math.max( + handleHeight, + kMinInteractiveDimension, ); + final Offset anchor = _selectionOverlay!.selectionControls! + .getHandleAnchor( + TextSelectionHandleType.collapsed, + lineHeight, + ); final double handleCenter = handleHeight / 2 - anchor.dy; - bottomSpacing = - math.max(handleCenter + interactiveHandleHeight / 2, bottomSpacing); + bottomSpacing = math.max( + handleCenter + interactiveHandleHeight / 2, + bottomSpacing, + ); } - final EdgeInsets caretPadding = - widget.scrollPadding.copyWith(bottom: bottomSpacing); + final EdgeInsets caretPadding = widget.scrollPadding.copyWith( + bottom: bottomSpacing, + ); - final Rect caretRect = - renderEditable.getLocalRectForCaret(renderEditable.selection!.extent); + final Rect caretRect = renderEditable.getLocalRectForCaret( + renderEditable.selection!.extent, + ); final RevealedOffset targetOffset = _getOffsetToRevealCaret(caretRect); final Rect rectToReveal; @@ -4169,8 +4314,8 @@ class EditableTextState extends State if (selection.isCollapsed) { rectToReveal = targetOffset.rect; } else { - final List selectionBoxes = - renderEditable.getBoxesForSelection(selection); + final List selectionBoxes = renderEditable + .getBoxesForSelection(selection); // selectionBoxes may be empty if, for example, the selection does not // encompass a full character, like if it only contained part of an // extended grapheme cluster. @@ -4197,7 +4342,8 @@ class EditableTextState extends State } else { _scrollController.jumpTo(targetOffset.offset); renderEditable.showOnScreen( - rect: caretPadding.inflateRect(rectToReveal)); + rect: caretPadding.inflateRect(rectToReveal), + ); } }, debugLabel: 'EditableText.showCaret'); } @@ -4287,7 +4433,8 @@ class EditableTextState extends State // will keep trying to modify the composing region while Gboard will keep // trying to restore the original composing region. try { - value = widget.inputFormatters?.fold( + value = + widget.inputFormatters?.fold( value, (TextEditingValue newValue, TextInputFormatter formatter) => formatter.formatEditUpdate(_value, newValue), @@ -4377,9 +4524,11 @@ class EditableTextState extends State widget.cursorColor.alpha / 255.0, _cursorBlinkOpacityController.value, ); - renderEditable.cursorColor = - widget.cursorColor.withOpacity(effectiveOpacity); - _cursorVisibilityNotifier.value = widget.showCursor && + renderEditable.cursorColor = widget.cursorColor.withOpacity( + effectiveOpacity, + ); + _cursorVisibilityNotifier.value = + widget.showCursor && (EditableText.debugDeterministicCursor || _cursorBlinkOpacityController.value > 0); } @@ -4440,8 +4589,8 @@ class EditableTextState extends State if (_obscureShowCharTicksPending > 0) { _obscureShowCharTicksPending = WidgetsBinding.instance.platformDispatcher.brieflyShowPassword - ? _obscureShowCharTicksPending - 1 - : 0; + ? _obscureShowCharTicksPending - 1 + : 0; if (_obscureShowCharTicksPending == 0) { setState(() {}); } @@ -4471,8 +4620,9 @@ class EditableTextState extends State void _stopCursorBlink({bool resetCharTicks = true}) { // If the cursor is animating, stop the animation, and we always // want the cursor to be visible when the floating cursor is enabled. - _cursorBlinkOpacityController.value = - renderEditable.floatingCursorOn ? 1.0 : 0.0; + _cursorBlinkOpacityController.value = renderEditable.floatingCursorOn + ? 1.0 + : 0.0; _cursorTimer?.cancel(); _cursorTimer = null; if (resetCharTicks) { @@ -4538,14 +4688,13 @@ class EditableTextState extends State final bool isDesktop = switch (defaultTargetPlatform) { TargetPlatform.android || TargetPlatform.iOS || - TargetPlatform.fuchsia => - false, + TargetPlatform.fuchsia => false, TargetPlatform.macOS || TargetPlatform.linux || - TargetPlatform.windows => - true, + TargetPlatform.windows => true, }; - final bool shouldSelectAll = widget.selectionEnabled && + final bool shouldSelectAll = + widget.selectionEnabled && (kIsWeb || isDesktop) && !_isMultiline && !_nextFocusChangeIsInternal && @@ -4554,8 +4703,10 @@ class EditableTextState extends State if (shouldSelectAll) { // On native web and desktop platforms, single line tags // select all when receiving focus. - selection = - TextSelection(baseOffset: 0, extentOffset: _value.text.length); + selection = TextSelection( + baseOffset: 0, + extentOffset: _value.text.length, + ); } else if (!_value.selection.isValid) { // Place cursor at the end if the selection is invalid when we receive focus. selection = TextSelection.collapsed(offset: _value.text.length); @@ -4611,11 +4762,14 @@ class EditableTextState extends State } final InlineSpan inlineSpan = renderEditable.text!; - final TextScaler effectiveTextScaler = - switch ((widget.textScaler, widget.textScaleFactor)) { + final TextScaler effectiveTextScaler = switch (( + widget.textScaler, + widget.textScaleFactor, + )) { (final TextScaler textScaler, _) => textScaler, - (null, final double textScaleFactor) => - TextScaler.linear(textScaleFactor), + (null, final double textScaleFactor) => TextScaler.linear( + textScaleFactor, + ), (null, null) => MediaQuery.textScalerOf(context), }; @@ -4624,7 +4778,8 @@ class EditableTextState extends State textAlign: widget.textAlign, textDirection: _textDirection, textScaler: effectiveTextScaler, - textHeightBehavior: widget.textHeightBehavior ?? + textHeightBehavior: + widget.textHeightBehavior ?? DefaultTextHeightBehavior.maybeOf(context), locale: widget.locale, structStyle: widget.strutStyle, @@ -4644,8 +4799,9 @@ class EditableTextState extends State int graphemeStart = 0; // Can't use _value.text here: the controller value could change between // frames. - final String plainText = - inlineSpan.toPlainText(includeSemanticsLabels: false); + final String plainText = inlineSpan.toPlainText( + includeSemanticsLabels: false, + ); final CharacterRange characterRange = CharacterRange(plainText); while (characterRange.moveNext()) { final int graphemeEnd = graphemeStart + characterRange.current.length; @@ -4668,9 +4824,10 @@ class EditableTextState extends State // At least some part of the letter is visible within the text field. rects.add( SelectionRect( - position: graphemeStart, - bounds: box.toRect(), - direction: box.direction), + position: graphemeStart, + bounds: box.toRect(), + direction: box.direction, + ), ); } } @@ -4689,13 +4846,15 @@ class EditableTextState extends State void _updateComposingRectIfNeeded() { final TextRange composingRange = _value.composing; assert(mounted); - Rect? composingRect = - renderEditable.getRectForComposingRange(composingRange); + Rect? composingRect = renderEditable.getRectForComposingRange( + composingRange, + ); // Send the caret location instead if there's no marked text yet. if (composingRect == null) { final int offset = composingRange.isValid ? composingRange.start : 0; - composingRect = - renderEditable.getLocalRectForCaret(TextPosition(offset: offset)); + composingRect = renderEditable.getLocalRectForCaret( + TextPosition(offset: offset), + ); } _textInputConnection!.setComposingRect(composingRect); } @@ -4717,10 +4876,12 @@ class EditableTextState extends State if (selection == null || !selection.isValid) { return; } - final TextPosition currentTextPosition = - TextPosition(offset: selection.start); - final Rect caretRect = - renderEditable.getLocalRectForCaret(currentTextPosition); + final TextPosition currentTextPosition = TextPosition( + offset: selection.start, + ); + final Rect caretRect = renderEditable.getLocalRectForCaret( + currentTextPosition, + ); _textInputConnection!.setCaretRect(caretRect); } @@ -4741,11 +4902,14 @@ class EditableTextState extends State @override void userUpdateTextEditingValue( - TextEditingValue value, SelectionChangedCause? cause) { + TextEditingValue value, + SelectionChangedCause? cause, + ) { // Compare the current TextEditingValue with the pre-format new // TextEditingValue value, in case the formatter would reject the change. - final bool shouldShowCaret = - widget.readOnly ? _value.selection != value.selection : _value != value; + final bool shouldShowCaret = widget.readOnly + ? _value.selection != value.selection + : _value != value; if (shouldShowCaret) { scheduleShowCaretOnScreen(withAnimation: true); } @@ -4802,11 +4966,13 @@ class EditableTextState extends State // hidden during a scroll on supported platforms. if (_platformSupportsFadeOnScroll) { _listeningToScrollNotificationObserver = true; - _scrollNotificationObserver - ?.removeListener(_handleContextMenuOnParentScroll); + _scrollNotificationObserver?.removeListener( + _handleContextMenuOnParentScroll, + ); _scrollNotificationObserver = ScrollNotificationObserver.maybeOf(context); - _scrollNotificationObserver - ?.addListener(_handleContextMenuOnParentScroll); + _scrollNotificationObserver?.addListener( + _handleContextMenuOnParentScroll, + ); } return true; } @@ -4826,8 +4992,8 @@ class EditableTextState extends State /// Toggles the visibility of the toolbar. void toggleToolbar([bool hideHandles = true]) { - final TextSelectionOverlay selectionOverlay = - _selectionOverlay ??= _createSelectionOverlay(); + final TextSelectionOverlay selectionOverlay = _selectionOverlay ??= + _createSelectionOverlay(); if (selectionOverlay.toolbarIsVisible) { hideToolbar(hideHandles); } else { @@ -4848,7 +5014,8 @@ class EditableTextState extends State _selectionOverlay == null || !_spellCheckResultsReceived || findSuggestionSpanAtCursorIndex( - textEditingValue.selection.extentOffset) == + textEditingValue.selection.extentOffset, + ) == null) { // Only attempt to show the spell check suggestions toolbar if there // is a toolbar specified and spell check suggestions available to show. @@ -4864,7 +5031,9 @@ class EditableTextState extends State _selectionOverlay!.showSpellCheckSuggestionsToolbar((BuildContext context) { return _spellCheckConfiguration.spellCheckSuggestionsToolbarBuilder!( - context, this); + context, + this, + ); }); return true; } @@ -4953,8 +5122,9 @@ class EditableTextState extends State @override TextInputConfiguration get textInputConfiguration { - final List? autofillHints = - widget.autofillHints?.toList(growable: false); + final List? autofillHints = widget.autofillHints?.toList( + growable: false, + ); final AutofillConfiguration autofillConfiguration = autofillHints != null ? AutofillConfiguration( uniqueIdentifier: autofillId, @@ -4975,7 +5145,8 @@ class EditableTextState extends State smartQuotesType: widget.smartQuotesType, enableSuggestions: widget.enableSuggestions, enableInteractiveSelection: widget._userSelectionEnabled, - inputAction: widget.textInputAction ?? + inputAction: + widget.textInputAction ?? (widget.keyboardType == TextInputType.multiline ? TextInputAction.newline : TextInputAction.done), @@ -5008,7 +5179,7 @@ class EditableTextState extends State (widget.selectionControls is TextSelectionHandleControls ? copyEnabled : copyEnabled && - (widget.selectionControls?.canCopy(this) ?? false)) + (widget.selectionControls?.canCopy(this) ?? false)) ? () { controls?.handleCopy(this); copySelection(SelectionChangedCause.toolbar); @@ -5022,7 +5193,7 @@ class EditableTextState extends State (widget.selectionControls is TextSelectionHandleControls ? cutEnabled : cutEnabled && - (widget.selectionControls?.canCut(this) ?? false)) + (widget.selectionControls?.canCut(this) ?? false)) ? () { controls?.handleCut(this); cutSelection(SelectionChangedCause.toolbar); @@ -5036,7 +5207,7 @@ class EditableTextState extends State (widget.selectionControls is TextSelectionHandleControls ? pasteEnabled : pasteEnabled && - (widget.selectionControls?.canPaste(this) ?? false)) && + (widget.selectionControls?.canPaste(this) ?? false)) && (clipboardStatus.value == ClipboardStatus.pasteable) ? () { controls?.handlePaste(this); @@ -5056,7 +5227,7 @@ class EditableTextState extends State assert(extent.offset >= 0); final int newOffset = forward ? textBoundary.getTrailingTextBoundaryAt(extent.offset) ?? - _value.text.length + _value.text.length // if x is a boundary defined by `textBoundary`, most textBoundaries (except // LineBreaker) guarantees `x == textBoundary.getLeadingTextBoundaryAt(x)`. // Use x - 1 here to make sure we don't get stuck at the fixed point x. @@ -5072,7 +5243,10 @@ class EditableTextState extends State // exclusively for handling line boundaries, since performing "move to line // start" more than once usually doesn't move you to the previous line. TextPosition _moveToTextBoundary( - TextPosition extent, bool forward, TextBoundary textBoundary) { + TextPosition extent, + bool forward, + TextBoundary textBoundary, + ) { assert(extent.offset >= 0); final int caretOffset; switch (extent.affinity) { @@ -5099,12 +5273,14 @@ class EditableTextState extends State // processing needed since the LineBoundary class does exactly that. return forward ? TextPosition( - offset: textBoundary.getTrailingTextBoundaryAt(caretOffset) ?? + offset: + textBoundary.getTrailingTextBoundaryAt(caretOffset) ?? _value.text.length, affinity: TextAffinity.upstream, ) : TextPosition( - offset: textBoundary.getLeadingTextBoundaryAt(caretOffset) ?? 0); + offset: textBoundary.getLeadingTextBoundaryAt(caretOffset) ?? 0, + ); } // --------------------------- Text Editing Actions --------------------------- @@ -5122,7 +5298,9 @@ class EditableTextState extends State Action _makeOverridable(Action defaultAction) { return Action.overridable( - context: context, defaultAction: defaultAction); + context: context, + defaultAction: defaultAction, + ); } /// Transpose the characters immediately before and after the current @@ -5142,8 +5320,10 @@ class EditableTextState extends State final String text = _value.text; final TextSelection selection = _value.selection; final bool atEnd = selection.baseOffset == text.length; - final CharacterRange transposing = - CharacterRange.at(text, selection.baseOffset); + final CharacterRange transposing = CharacterRange.at( + text, + selection.baseOffset, + ); if (atEnd) { transposing.moveBack(2); } else { @@ -5155,7 +5335,8 @@ class EditableTextState extends State userUpdateTextEditingValue( TextEditingValue( - text: transposing.stringBefore + + text: + transposing.stringBefore + transposing.currentCharacters.last + transposing.currentCharacters.first + transposing.stringAfter, @@ -5182,7 +5363,8 @@ class EditableTextState extends State oldText: oldValue.text, deletedRange: intent.replacementRange, selection: TextSelection.collapsed( - offset: intent.replacementRange.start), + offset: intent.replacementRange.start, + ), composing: TextRange.empty, ) : TextEditingDeltaReplacement( @@ -5190,7 +5372,8 @@ class EditableTextState extends State replacementText: intent.replacementText, replacedRange: intent.replacementRange, selection: TextSelection.collapsed( - offset: intent.replacementRange.start), + offset: intent.replacementRange.start, + ), composing: TextRange.empty, ), ); @@ -5213,8 +5396,8 @@ class EditableTextState extends State late final Action _replaceTextAction = CallbackAction( - onInvoke: _replaceText, - ); + onInvoke: _replaceText, + ); // Scrolls either to the beginning or end of the document depending on the // intent's `forward` parameter. @@ -5247,8 +5430,10 @@ class EditableTextState extends State final ScrollableState? state = _scrollableKey.currentState as ScrollableState?; - final double increment = - ScrollAction.getDirectionalIncrement(state!, intent); + final double increment = ScrollAction.getDirectionalIncrement( + state!, + intent, + ); final double destination = clampDouble( position.pixels + increment, position.minScrollExtent, @@ -5268,8 +5453,9 @@ class EditableTextState extends State } final TextSelection nextSelection; - final Rect extentRect = - renderEditable.getLocalRectForCaret(_value.selection.extent); + final Rect extentRect = renderEditable.getLocalRectForCaret( + _value.selection.extent, + ); final ScrollableState? state = _scrollableKey.currentState as ScrollableState?; final double increment = ScrollAction.getDirectionalIncrement( @@ -5284,29 +5470,37 @@ class EditableTextState extends State if (_value.selection.extentOffset >= _value.text.length) { return; } - final Offset nextExtentOffset = - Offset(extentRect.left, extentRect.top + increment); + final Offset nextExtentOffset = Offset( + extentRect.left, + extentRect.top + increment, + ); final double height = position.maxScrollExtent + renderEditable.size.height; final TextPosition nextExtent = nextExtentOffset.dy + position.pixels >= height - ? TextPosition(offset: _value.text.length) - : renderEditable.getPositionForPoint( - renderEditable.localToGlobal(nextExtentOffset)); - nextSelection = - _value.selection.copyWith(extentOffset: nextExtent.offset); + ? TextPosition(offset: _value.text.length) + : renderEditable.getPositionForPoint( + renderEditable.localToGlobal(nextExtentOffset), + ); + nextSelection = _value.selection.copyWith( + extentOffset: nextExtent.offset, + ); } else { if (_value.selection.extentOffset <= 0) { return; } - final Offset nextExtentOffset = - Offset(extentRect.left, extentRect.top + increment); + final Offset nextExtentOffset = Offset( + extentRect.left, + extentRect.top + increment, + ); final TextPosition nextExtent = nextExtentOffset.dy + position.pixels <= 0 ? const TextPosition(offset: 0) : renderEditable.getPositionForPoint( - renderEditable.localToGlobal(nextExtentOffset)); - nextSelection = - _value.selection.copyWith(extentOffset: nextExtent.offset); + renderEditable.localToGlobal(nextExtentOffset), + ); + nextSelection = _value.selection.copyWith( + extentOffset: nextExtent.offset, + ); } bringIntoView(nextSelection.extent); @@ -5347,9 +5541,12 @@ class EditableTextState extends State CallbackAction(onInvoke: _updateSelection); late final _UpdateTextSelectionVerticallyAction< - DirectionalCaretMovementIntent> _verticalSelectionUpdateAction = + DirectionalCaretMovementIntent + > + _verticalSelectionUpdateAction = _UpdateTextSelectionVerticallyAction( - this); + this, + ); Object? _hideToolbarIfVisible(DismissIntent intent) { if (_selectionOverlay?.toolbarIsVisible ?? false) { @@ -5391,7 +5588,9 @@ class EditableTextState extends State Actions.invoke( context, EditableTextTapOutsideIntent( - focusNode: widget.focusNode, pointerDownEvent: event), + focusNode: widget.focusNode, + pointerDownEvent: event, + ), ); } @@ -5402,7 +5601,9 @@ class EditableTextState extends State Actions.invoke( context, EditableTextTapUpOutsideIntent( - focusNode: widget.focusNode, pointerUpEvent: event), + focusNode: widget.focusNode, + pointerUpEvent: event, + ), ); } @@ -5411,8 +5612,9 @@ class EditableTextState extends State ReplaceTextIntent: _replaceTextAction, UpdateSelectionIntent: _updateSelectionAction, DirectionalFocusIntent: DirectionalFocusAction.forTextField(), - DismissIntent: - CallbackAction(onInvoke: _hideToolbarIfVisible), + DismissIntent: CallbackAction( + onInvoke: _hideToolbarIfVisible, + ), // Delete DeleteCharacterIntent: _makeOverridable( @@ -5431,7 +5633,10 @@ class EditableTextState extends State ), DeleteToLineBreakIntent: _makeOverridable( _DeleteTextAction( - this, _linebreak, _moveToTextBoundary), + this, + _linebreak, + _moveToTextBoundary, + ), ), // Extend/Move Selection @@ -5445,7 +5650,8 @@ class EditableTextState extends State ), ExtendSelectionByPageIntent: _makeOverridable( CallbackAction( - onInvoke: _extendSelectionByPage), + onInvoke: _extendSelectionByPage, + ), ), ExtendSelectionToNextWordBoundaryIntent: _makeOverridable( _UpdateTextSelectionAction( @@ -5471,20 +5677,23 @@ class EditableTextState extends State ignoreNonCollapsedSelection: true, ), ), - ExtendSelectionVerticallyToAdjacentLineIntent: - _makeOverridable(_verticalSelectionUpdateAction), - ExtendSelectionVerticallyToAdjacentPageIntent: - _makeOverridable(_verticalSelectionUpdateAction), + ExtendSelectionVerticallyToAdjacentLineIntent: _makeOverridable( + _verticalSelectionUpdateAction, + ), + ExtendSelectionVerticallyToAdjacentPageIntent: _makeOverridable( + _verticalSelectionUpdateAction, + ), ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent: _makeOverridable( - _UpdateTextSelectionAction< - ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent>( - this, - _paragraphBoundary, - _moveBeyondTextBoundary, - ignoreNonCollapsedSelection: true, - ), - ), + _UpdateTextSelectionAction< + ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent + >( + this, + _paragraphBoundary, + _moveBeyondTextBoundary, + ignoreNonCollapsedSelection: true, + ), + ), ExtendSelectionToDocumentBoundaryIntent: _makeOverridable( _UpdateTextSelectionAction( this, @@ -5495,7 +5704,8 @@ class EditableTextState extends State ), ExtendSelectionToNextWordBoundaryOrCaretLocationIntent: _makeOverridable( _UpdateTextSelectionAction< - ExtendSelectionToNextWordBoundaryOrCaretLocationIntent>( + ExtendSelectionToNextWordBoundaryOrCaretLocationIntent + >( this, _nextWordBoundary, _moveBeyondTextBoundary, @@ -5504,7 +5714,8 @@ class EditableTextState extends State ), ScrollToDocumentBoundaryIntent: _makeOverridable( CallbackAction( - onInvoke: _scrollToDocumentBoundary), + onInvoke: _scrollToDocumentBoundary, + ), ), ScrollIntent: CallbackAction(onInvoke: _scroll), @@ -5539,10 +5750,12 @@ class EditableTextState extends State ), TransposeCharactersIntent: _makeOverridable(_transposeCharactersAction), - EditableTextTapOutsideIntent: - _makeOverridable(_EditableTextTapOutsideAction()), - EditableTextTapUpOutsideIntent: - _makeOverridable(_EditableTextTapUpOutsideAction()), + EditableTextTapOutsideIntent: _makeOverridable( + _EditableTextTapOutsideAction(), + ), + EditableTextTapUpOutsideIntent: _makeOverridable( + _EditableTextTapUpOutsideAction(), + ), }; @protected @@ -5552,11 +5765,14 @@ class EditableTextState extends State super.build(context); // See AutomaticKeepAliveClientMixin. final TextSelectionControls? controls = widget.selectionControls; - final TextScaler effectiveTextScaler = - switch ((widget.textScaler, widget.textScaleFactor)) { + final TextScaler effectiveTextScaler = switch (( + widget.textScaler, + widget.textScaleFactor, + )) { (final TextScaler textScaler, _) => textScaler, - (null, final double textScaleFactor) => - TextScaler.linear(textScaleFactor), + (null, final double textScaleFactor) => TextScaler.linear( + textScaleFactor, + ), (null, null) => MediaQuery.textScalerOf(context), }; final ui.SemanticsInputType inputType; @@ -5592,38 +5808,44 @@ class EditableTextState extends State value: widget.controller, onTriggered: (TextEditingValue value) { userUpdateTextEditingValue( - value, SelectionChangedCause.keyboard); + value, + SelectionChangedCause.keyboard, + ); }, shouldChangeUndoStack: (TextEditingValue? oldValue, TextEditingValue newValue) { - if (!newValue.selection.isValid) { - return false; - } - - if (oldValue == null) { - return true; - } - - switch (defaultTargetPlatform) { - case TargetPlatform.iOS: - case TargetPlatform.macOS: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - // Composing text is not counted in history coalescing. - if (!widget.controller.value.composing.isCollapsed) { + if (!newValue.selection.isValid) { return false; } - case TargetPlatform.android: - // Gboard on Android puts non-CJK words in composing regions. Coalesce - // composing text in order to allow the saving of partial words in that - // case. - break; - } - return oldValue.text != newValue.text || - oldValue.composing != newValue.composing; - }, + if (oldValue == null) { + return true; + } + + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + case TargetPlatform.macOS: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + // Composing text is not counted in history coalescing. + if (!widget + .controller + .value + .composing + .isCollapsed) { + return false; + } + case TargetPlatform.android: + // Gboard on Android puts non-CJK words in composing regions. Coalesce + // composing text in order to allow the saving of partial words in that + // case. + break; + } + + return oldValue.text != newValue.text || + oldValue.composing != newValue.composing; + }, undoStackModifier: (TextEditingValue value) { // On Android we should discard the composing region when pushing // a new entry to the undo stack. This prevents the TextInputPlugin @@ -5658,94 +5880,101 @@ class EditableTextState extends State // If a ScrollBehavior is not provided, only apply scrollbars when // multiline. The overscroll indicator should not be applied in // either case, glowing or stretching. - scrollBehavior: widget.scrollBehavior ?? + scrollBehavior: + widget.scrollBehavior ?? ScrollConfiguration.of( context, ).copyWith( - scrollbars: _isMultiline, overscroll: false), + scrollbars: _isMultiline, + overscroll: false, + ), viewportBuilder: (BuildContext context, ViewportOffset offset) { - return CompositedTransformTarget( - link: _toolbarLayerLink, - child: Semantics( - inputType: inputType, - onCopy: _semanticsOnCopy(controls), - onCut: _semanticsOnCut(controls), - onPaste: _semanticsOnPaste(controls), - child: _ScribbleFocusable( - editableKey: _editableKey, - enabled: _stylusHandwritingEnabled, - focusNode: widget.focusNode, - updateSelectionRects: () { - _openInputConnection(); - _updateSelectionRects(force: true); - }, - child: SizeChangedLayoutNotifier( - child: _Editable( - key: _editableKey, - controller: widget.controller, - startHandleLayerLink: _startHandleLayerLink, - endHandleLayerLink: _endHandleLayerLink, - inlineSpan: buildTextSpan(), - value: _value, - cursorColor: _cursorColor, - backgroundCursorColor: - widget.backgroundCursorColor, - showCursor: _cursorVisibilityNotifier, - forceLine: widget.forceLine, - readOnly: widget.readOnly, - hasFocus: _hasFocus, - maxLines: widget.maxLines, - minLines: widget.minLines, - expands: widget.expands, - strutStyle: widget.strutStyle, - selectionColor: _selectionOverlay - ?.spellCheckToolbarIsVisible ?? - false - ? _spellCheckConfiguration - .misspelledSelectionColor ?? - widget.selectionColor - : widget.selectionColor, - textScaler: effectiveTextScaler, - textAlign: widget.textAlign, - textDirection: _textDirection, - locale: widget.locale, - textHeightBehavior: - widget.textHeightBehavior ?? + return CompositedTransformTarget( + link: _toolbarLayerLink, + child: Semantics( + inputType: inputType, + onCopy: _semanticsOnCopy(controls), + onCut: _semanticsOnCut(controls), + onPaste: _semanticsOnPaste(controls), + child: _ScribbleFocusable( + editableKey: _editableKey, + enabled: _stylusHandwritingEnabled, + focusNode: widget.focusNode, + updateSelectionRects: () { + _openInputConnection(); + _updateSelectionRects(force: true); + }, + child: SizeChangedLayoutNotifier( + child: _Editable( + key: _editableKey, + controller: widget.controller, + startHandleLayerLink: + _startHandleLayerLink, + endHandleLayerLink: _endHandleLayerLink, + inlineSpan: buildTextSpan(), + value: _value, + cursorColor: _cursorColor, + backgroundCursorColor: + widget.backgroundCursorColor, + showCursor: _cursorVisibilityNotifier, + forceLine: widget.forceLine, + readOnly: widget.readOnly, + hasFocus: _hasFocus, + maxLines: widget.maxLines, + minLines: widget.minLines, + expands: widget.expands, + strutStyle: widget.strutStyle, + selectionColor: + _selectionOverlay + ?.spellCheckToolbarIsVisible ?? + false + ? _spellCheckConfiguration + .misspelledSelectionColor ?? + widget.selectionColor + : widget.selectionColor, + textScaler: effectiveTextScaler, + textAlign: widget.textAlign, + textDirection: _textDirection, + locale: widget.locale, + textHeightBehavior: + widget.textHeightBehavior ?? DefaultTextHeightBehavior.maybeOf( - context), - textWidthBasis: widget.textWidthBasis, - obscuringCharacter: - widget.obscuringCharacter, - obscureText: widget.obscureText, - offset: offset, - rendererIgnoresPointer: - widget.rendererIgnoresPointer, - cursorWidth: widget.cursorWidth, - cursorHeight: widget.cursorHeight, - cursorRadius: widget.cursorRadius, - cursorOffset: - widget.cursorOffset ?? Offset.zero, - selectionHeightStyle: - widget.selectionHeightStyle, - selectionWidthStyle: - widget.selectionWidthStyle, - paintCursorAboveText: - widget.paintCursorAboveText, - enableInteractiveSelection: - widget._userSelectionEnabled, - textSelectionDelegate: this, - devicePixelRatio: _devicePixelRatio, - promptRectRange: _currentPromptRectRange, - promptRectColor: - widget.autocorrectionTextRectColor, - clipBehavior: widget.clipBehavior, + context, + ), + textWidthBasis: widget.textWidthBasis, + obscuringCharacter: + widget.obscuringCharacter, + obscureText: widget.obscureText, + offset: offset, + rendererIgnoresPointer: + widget.rendererIgnoresPointer, + cursorWidth: widget.cursorWidth, + cursorHeight: widget.cursorHeight, + cursorRadius: widget.cursorRadius, + cursorOffset: + widget.cursorOffset ?? Offset.zero, + selectionHeightStyle: + widget.selectionHeightStyle, + selectionWidthStyle: + widget.selectionWidthStyle, + paintCursorAboveText: + widget.paintCursorAboveText, + enableInteractiveSelection: + widget._userSelectionEnabled, + textSelectionDelegate: this, + devicePixelRatio: _devicePixelRatio, + promptRectRange: + _currentPromptRectRange, + promptRectColor: + widget.autocorrectionTextRectColor, + clipBehavior: widget.clipBehavior, + ), + ), ), ), - ), - ), - ); - }, + ); + }, ), ), ), @@ -5774,10 +6003,11 @@ class EditableTextState extends State }; final bool brieflyShowPassword = WidgetsBinding.instance.platformDispatcher.brieflyShowPassword && - mobilePlatforms.contains(defaultTargetPlatform); + mobilePlatforms.contains(defaultTargetPlatform); if (brieflyShowPassword) { - final int? o = - _obscureShowCharTicksPending > 0 ? _obscureLatestCharIndex : null; + final int? o = _obscureShowCharTicksPending > 0 + ? _obscureLatestCharIndex + : null; if (o != null && o >= 0 && o < text.length) { text = text.replaceRange(o, o + 1, _value.text.substring(o, o + 1)); } @@ -5790,8 +6020,9 @@ class EditableTextState extends State final int placeholderLocation = _value.text.length - _placeholderLocation; if (_isMultiline) { // The zero size placeholder here allows the line to break and keep the caret on the first line. - placeholders.add(const _ScribblePlaceholder( - child: SizedBox.shrink(), size: Size.zero)); + placeholders.add( + const _ScribblePlaceholder(child: SizedBox.shrink(), size: Size.zero), + ); placeholders.add( _ScribblePlaceholder( child: const SizedBox.shrink(), @@ -5801,7 +6032,9 @@ class EditableTextState extends State } else { placeholders.add( const _ScribblePlaceholder( - child: SizedBox.shrink(), size: Size(100.0, 0.0)), + child: SizedBox.shrink(), + size: Size(100.0, 0.0), + ), ); } return TextSpan( @@ -5818,9 +6051,11 @@ class EditableTextState extends State // If the composing range is out of range for the current text, ignore it to // preserve the tree integrity, otherwise in release mode a RangeError will // be thrown and this EditableText will be built with a broken subtree. - assert(!_value.composing.isValid || - !withComposing || - _value.isComposingRangeValid); + assert( + !_value.composing.isValid || + !withComposing || + _value.isComposingRangeValid, + ); final bool composingRegionOutOfRange = !_value.isComposingRangeValid || !withComposing; @@ -5886,7 +6121,8 @@ class _Editable extends MultiChildRenderObjectWidget { required this.clipBehavior, required this.controller, }) : super( - children: WidgetSpan.extractFromInlineSpan(inlineSpan, textScaler)); + children: WidgetSpan.extractFromInlineSpan(inlineSpan, textScaler), + ); final InlineSpan inlineSpan; final TextEditingValue value; @@ -6045,7 +6281,8 @@ class _ScribbleCacheKey { if (identical(other, this)) { return RenderComparison.identical; } - final bool needsLayout = textAlign != other.textAlign || + final bool needsLayout = + textAlign != other.textAlign || textDirection != other.textDirection || textScaler != other.textScaler || (textHeightBehavior ?? const TextHeightBehavior()) != @@ -6082,7 +6319,7 @@ class _ScribbleFocusable extends StatefulWidget { class _ScribbleFocusableState extends State<_ScribbleFocusable> implements ScribbleClient { _ScribbleFocusableState() - : _elementIdentifier = (_nextElementIdentifier++).toString(); + : _elementIdentifier = (_nextElementIdentifier++).toString(); @override void initState() { @@ -6123,7 +6360,9 @@ class _ScribbleFocusableState extends State<_ScribbleFocusable> void onScribbleFocus(Offset offset) { widget.focusNode.requestFocus(); renderEditable?.selectPositionAt( - from: offset, cause: SelectionChangedCause.stylusHandwriting); + from: offset, + cause: SelectionChangedCause.stylusHandwriting, + ); widget.updateSelectionRects(); } @@ -6141,10 +6380,14 @@ class _ScribbleFocusableState extends State<_ScribbleFocusable> } final Rect intersection = calculatedBounds.intersect(rect); final HitTestResult result = HitTestResult(); - WidgetsBinding.instance - .hitTestInView(result, intersection.center, View.of(context).viewId); - return result.path - .any((HitTestEntry entry) => entry.target == renderEditable); + WidgetsBinding.instance.hitTestInView( + result, + intersection.center, + View.of(context).viewId, + ); + return result.path.any( + (HitTestEntry entry) => entry.target == renderEditable, + ); } @override @@ -6301,7 +6544,8 @@ class _DeleteTextAction if (!selection.isCollapsed) { // Expands the selection to ensure the range covers full graphemes. final TextRange range = TextRange( - start: atomicBoundary.getLeadingTextBoundaryAt(selection.start) ?? + start: + atomicBoundary.getLeadingTextBoundaryAt(selection.start) ?? state._value.text.length, end: atomicBoundary.getTrailingTextBoundaryAt(selection.end - 1) ?? 0, ); @@ -6315,17 +6559,20 @@ class _DeleteTextAction return Actions.invoke(context!, replaceTextIntent); } - final int target = - _applyTextBoundary(selection.base, intent.forward, getTextBoundary()) - .offset; + final int target = _applyTextBoundary( + selection.base, + intent.forward, + getTextBoundary(), + ).offset; final TextRange rangeToDelete = TextSelection( baseOffset: intent.forward ? atomicBoundary.getLeadingTextBoundaryAt(selection.baseOffset) ?? - state._value.text.length - : atomicBoundary - .getTrailingTextBoundaryAt(selection.baseOffset - 1) ?? - 0, + state._value.text.length + : atomicBoundary.getTrailingTextBoundaryAt( + selection.baseOffset - 1, + ) ?? + 0, extentOffset: target, ); final ReplaceTextIntent replaceTextIntent = ReplaceTextIntent( @@ -6403,7 +6650,8 @@ class _UpdateTextSelectionAction UpdateSelectionIntent( state._value, TextSelection.collapsed( - offset: intent.forward ? selection.end : selection.start), + offset: intent.forward ? selection.end : selection.start, + ), SelectionChangedCause.keyboard, ), ); @@ -6417,11 +6665,14 @@ class _UpdateTextSelectionAction extent = TextPosition(offset: extent.offset); } else if (!intent.forward && _isAtWordwrapDownstream(extent)) { extent = TextPosition( - offset: extent.offset, affinity: TextAffinity.upstream); + offset: extent.offset, + affinity: TextAffinity.upstream, + ); } } - final bool shouldTargetBase = isExpand && + final bool shouldTargetBase = + isExpand && (intent.forward ? selection.baseOffset > selection.extentOffset : selection.baseOffset < selection.extentOffset); @@ -6430,15 +6681,16 @@ class _UpdateTextSelectionAction intent.forward, getTextBoundary(), ); - final TextSelection newSelection = collapseSelection || + final TextSelection newSelection = + collapseSelection || (!isExpand && newExtent.offset == selection.baseOffset) ? TextSelection.fromPosition(newExtent) : isExpand - ? selection.expandTo( - newExtent, extentAtIndex || selection.isCollapsed) - : selection.extendTo(newExtent); + ? selection.expandTo(newExtent, extentAtIndex || selection.isCollapsed) + : selection.extendTo(newExtent); - final bool shouldCollapseToBase = intent.collapseAtReversal && + final bool shouldCollapseToBase = + intent.collapseAtReversal && (selection.baseOffset - selection.extentOffset) * (selection.baseOffset - newSelection.extentOffset) < 0; @@ -6448,7 +6700,10 @@ class _UpdateTextSelectionAction return Actions.invoke( context!, UpdateSelectionIntent( - state._value, newRange, SelectionChangedCause.keyboard), + state._value, + newRange, + SelectionChangedCause.keyboard, + ), ); } @@ -6457,7 +6712,9 @@ class _UpdateTextSelectionAction } class _UpdateTextSelectionVerticallyAction< - T extends DirectionalCaretMovementIntent> extends ContextAction { + T extends DirectionalCaretMovementIntent +> + extends ContextAction { _UpdateTextSelectionVerticallyAction(this.state); final EditableTextState state; @@ -6473,7 +6730,8 @@ class _UpdateTextSelectionVerticallyAction< } _runSelection = state._value.selection; final TextSelection currentSelection = state.widget.controller.selection; - final bool continueCurrentRun = currentSelection.isValid && + final bool continueCurrentRun = + currentSelection.isValid && currentSelection.isCollapsed && currentSelection.baseOffset == runSelection.baseOffset && currentSelection.extentOffset == runSelection.extentOffset; @@ -6499,23 +6757,25 @@ class _UpdateTextSelectionVerticallyAction< _runSelection = null; } - final VerticalCaretMovementRun currentRun = _verticalMovementRun ?? - state.renderEditable - .startVerticalCaretMovement(state.renderEditable.selection!.extent); + final VerticalCaretMovementRun currentRun = + _verticalMovementRun ?? + state.renderEditable.startVerticalCaretMovement( + state.renderEditable.selection!.extent, + ); - final bool shouldMove = intent - is ExtendSelectionVerticallyToAdjacentPageIntent + final bool shouldMove = + intent is ExtendSelectionVerticallyToAdjacentPageIntent ? currentRun.moveByOffset( (intent.forward ? 1.0 : -1.0) * state.renderEditable.size.height, ) : intent.forward - ? currentRun.moveNext() - : currentRun.movePrevious(); + ? currentRun.moveNext() + : currentRun.movePrevious(); final TextPosition newExtent = shouldMove ? currentRun.current : intent.forward - ? TextPosition(offset: value.text.length) - : const TextPosition(offset: 0); + ? TextPosition(offset: value.text.length) + : const TextPosition(offset: 0); final TextSelection newSelection = collapseSelection ? TextSelection.fromPosition(newExtent) : value.selection.extendTo(newExtent); @@ -6523,7 +6783,10 @@ class _UpdateTextSelectionVerticallyAction< Actions.invoke( context!, UpdateSelectionIntent( - value, newSelection, SelectionChangedCause.keyboard), + value, + newSelection, + SelectionChangedCause.keyboard, + ), ); if (state._value.selection == newSelection) { _verticalMovementRun = currentRun; @@ -6615,7 +6878,8 @@ class _EditableTextTapOutsideAction intent.focusNode.unfocus(); case ui.PointerDeviceKind.trackpad: throw UnimplementedError( - 'Unexpected pointer down event for trackpad'); + 'Unexpected pointer down event for trackpad', + ); } case TargetPlatform.linux: case TargetPlatform.macOS: diff --git a/lib/common/widgets/text_field/spell_check.dart b/lib/common/widgets/text_field/spell_check.dart index 699c904d9..bb6e5606a 100644 --- a/lib/common/widgets/text_field/spell_check.dart +++ b/lib/common/widgets/text_field/spell_check.dart @@ -12,7 +12,8 @@ import 'package:flutter/painting.dart'; import 'package:flutter/services.dart' show SpellCheckResults, SpellCheckService, SuggestionSpan, TextEditingValue; -import 'package:PiliPlus/common/widgets/text_field/editable_text.dart' show EditableTextContextMenuBuilder; +import 'package:PiliPlus/common/widgets/text_field/editable_text.dart' + show EditableTextContextMenuBuilder; /// Controls how spell check is performed for text input. /// @@ -32,11 +33,11 @@ class SpellCheckConfiguration { /// Creates a configuration that disables spell check. const SpellCheckConfiguration.disabled() - : _spellCheckEnabled = false, - spellCheckService = null, - spellCheckSuggestionsToolbarBuilder = null, - misspelledTextStyle = null, - misspelledSelectionColor = null; + : _spellCheckEnabled = false, + spellCheckService = null, + spellCheckSuggestionsToolbarBuilder = null, + misspelledTextStyle = null, + misspelledSelectionColor = null; /// The service used to fetch spell check results for text input. final SpellCheckService? spellCheckService; @@ -85,7 +86,7 @@ class SpellCheckConfiguration { misspelledTextStyle: misspelledTextStyle ?? this.misspelledTextStyle, spellCheckSuggestionsToolbarBuilder: spellCheckSuggestionsToolbarBuilder ?? - this.spellCheckSuggestionsToolbarBuilder, + this.spellCheckSuggestionsToolbarBuilder, ); } @@ -114,11 +115,11 @@ class SpellCheckConfiguration { @override int get hashCode => Object.hash( - spellCheckService, - misspelledTextStyle, - spellCheckSuggestionsToolbarBuilder, - _spellCheckEnabled, - ); + spellCheckService, + misspelledTextStyle, + spellCheckSuggestionsToolbarBuilder, + _spellCheckEnabled, + ); } // Methods for displaying spell check results: @@ -153,8 +154,9 @@ List _correctSpellCheckResults( // Try finding SuggestionSpan from resultsText in new text. final String escapedText = RegExp.escape(currentSpanText); final RegExp currentSpanTextRegexp = RegExp('\\b$escapedText\\b'); - final int foundIndex = - newText.substring(searchStart).indexOf(currentSpanTextRegexp); + final int foundIndex = newText + .substring(searchStart) + .indexOf(currentSpanTextRegexp); // Check whether word was found exactly where expected or elsewhere in the newText. final bool currentSpanFoundExactly = @@ -170,14 +172,17 @@ List _correctSpellCheckResults( // corrected results. final SuggestionSpan adjustedSpan = SuggestionSpan( TextRange( - start: currentSpan.range.start + offset, - end: currentSpan.range.end + offset), + start: currentSpan.range.start + offset, + end: currentSpan.range.end + offset, + ), currentSpan.suggestions, ); // Start search for the next misspelled word at the end of currentSpan. - searchStart = - math.min(currentSpan.range.end + 1 + offset, newText.length); + searchStart = math.min( + currentSpan.range.end + 1 + offset, + newText.length, + ); correctedSpellCheckResults.add(adjustedSpan); } else if (currentSpanFoundElsewhere) { // Word was pushed forward but not modified. @@ -302,7 +307,8 @@ List _buildSubtreesWithoutComposingRegion( endIndex = currentSpan.range.end < text.length ? currentSpan.range.end : text.length; - cursorInCurrentSpan = currentSpan.range.start <= cursorIndex && + cursorInCurrentSpan = + currentSpan.range.start <= cursorIndex && currentSpan.range.end >= cursorIndex; textSpanTreeChildren.add( TextSpan( @@ -346,7 +352,7 @@ List _buildSubtreesWithComposingRegion( final TextRange composingRegion = value.composing; final TextStyle composingTextStyle = style?.merge(const TextStyle(decoration: TextDecoration.underline)) ?? - const TextStyle(decoration: TextDecoration.underline); + const TextStyle(decoration: TextDecoration.underline); final TextStyle misspelledJointStyle = style?.merge(misspelledStyle) ?? misspelledStyle; bool textPointerWithinComposingRegion = false; @@ -364,8 +370,8 @@ List _buildSubtreesWithComposingRegion( : text.length; textPointerWithinComposingRegion = composingRegion.start >= textPointer && - composingRegion.end <= endIndex && - !composingWithinCurrentTextRange; + composingRegion.end <= endIndex && + !composingWithinCurrentTextRange; if (textPointerWithinComposingRegion) { _addComposingRegionTextSpans( @@ -378,8 +384,9 @@ List _buildSubtreesWithComposingRegion( ); textSpanTreeChildren.add( TextSpan( - style: style, - text: text.substring(composingRegion.end, endIndex)), + style: style, + text: text.substring(composingRegion.end, endIndex), + ), ); } else { textSpanTreeChildren.add( @@ -392,7 +399,8 @@ List _buildSubtreesWithComposingRegion( endIndex = currentSpan.range.end < text.length ? currentSpan.range.end : text.length; - currentSpanIsComposingRegion = textPointer >= composingRegion.start && + currentSpanIsComposingRegion = + textPointer >= composingRegion.start && endIndex <= composingRegion.end && !composingWithinCurrentTextRange; textSpanTreeChildren.add( @@ -426,8 +434,9 @@ List _buildSubtreesWithComposingRegion( if (composingRegion.end != text.length) { textSpanTreeChildren.add( TextSpan( - style: style, - text: text.substring(composingRegion.end, text.length)), + style: style, + text: text.substring(composingRegion.end, text.length), + ), ); } } else { @@ -450,8 +459,9 @@ void _addComposingRegionTextSpans( TextStyle? style, TextStyle composingTextStyle, ) { - treeChildren.add(TextSpan( - style: style, text: text.substring(start, composingRegion.start))); + treeChildren.add( + TextSpan(style: style, text: text.substring(start, composingRegion.start)), + ); treeChildren.add( TextSpan( style: composingTextStyle, diff --git a/lib/common/widgets/text_field/spell_check_suggestions_toolbar.dart b/lib/common/widgets/text_field/spell_check_suggestions_toolbar.dart index 7c79f68fb..9631bdcb6 100644 --- a/lib/common/widgets/text_field/spell_check_suggestions_toolbar.dart +++ b/lib/common/widgets/text_field/spell_check_suggestions_toolbar.dart @@ -31,9 +31,11 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { /// /// [buttonItems] must not contain more than four items, generally three /// suggestions and one delete button. - const SpellCheckSuggestionsToolbar( - {super.key, required this.anchor, required this.buttonItems}) - : assert(buttonItems.length <= _kMaxSuggestions + 1); + const SpellCheckSuggestionsToolbar({ + super.key, + required this.anchor, + required this.buttonItems, + }) : assert(buttonItems.length <= _kMaxSuggestions + 1); /// Constructs a [SpellCheckSuggestionsToolbar] with the default children for /// an [EditableText]. @@ -44,9 +46,9 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { SpellCheckSuggestionsToolbar.editableText({ super.key, required EditableTextState editableTextState, - }) : buttonItems = - buildButtonItems(editableTextState) ?? [], - anchor = getToolbarAnchor(editableTextState.contextMenuAnchors); + }) : buttonItems = + buildButtonItems(editableTextState) ?? [], + anchor = getToolbarAnchor(editableTextState.contextMenuAnchors); /// {@template flutter.material.SpellCheckSuggestionsToolbar.anchor} /// The focal point below which the toolbar attempts to position itself. @@ -72,12 +74,13 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { /// Builds the button items for the toolbar based on the available /// spell check suggestions. static List? buildButtonItems( - EditableTextState editableTextState) { + EditableTextState editableTextState, + ) { // Determine if composing region is misspelled. - final SuggestionSpan? spanAtCursorIndex = - editableTextState.findSuggestionSpanAtCursorIndex( - editableTextState.currentTextEditingValue.selection.baseOffset, - ); + final SuggestionSpan? spanAtCursorIndex = editableTextState + .findSuggestionSpanAtCursorIndex( + editableTextState.currentTextEditingValue.selection.baseOffset, + ); if (spanAtCursorIndex == null) { return null; @@ -86,8 +89,9 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { final List buttonItems = []; // Build suggestion buttons. - for (final String suggestion - in spanAtCursorIndex.suggestions.take(_kMaxSuggestions)) { + for (final String suggestion in spanAtCursorIndex.suggestions.take( + _kMaxSuggestions, + )) { buttonItems.add( ContextMenuButtonItem( onPressed: () { @@ -95,7 +99,10 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { return; } _replaceText( - editableTextState, suggestion, spanAtCursorIndex.range); + editableTextState, + suggestion, + spanAtCursorIndex.range, + ); }, label: suggestion, ), @@ -108,8 +115,11 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { if (!editableTextState.mounted) { return; } - _replaceText(editableTextState, '', - editableTextState.currentTextEditingValue.composing); + _replaceText( + editableTextState, + '', + editableTextState.currentTextEditingValue.composing, + ); }, type: ContextMenuButtonType.delete, ); @@ -124,22 +134,27 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { TextRange replacementRange, ) { // Replacement cannot be performed if the text is read only or obscured. - assert(!editableTextState.widget.readOnly && - !editableTextState.widget.obscureText); - - final TextEditingValue newValue = - editableTextState.textEditingValue.replaced( - replacementRange, - text, + assert( + !editableTextState.widget.readOnly && + !editableTextState.widget.obscureText, ); + + final TextEditingValue newValue = editableTextState.textEditingValue + .replaced( + replacementRange, + text, + ); editableTextState.userUpdateTextEditingValue( - newValue, SelectionChangedCause.toolbar); + newValue, + SelectionChangedCause.toolbar, + ); // Schedule a call to bringIntoView() after renderEditable updates. SchedulerBinding.instance.addPostFrameCallback((Duration duration) { if (editableTextState.mounted) { - editableTextState - .bringIntoView(editableTextState.textEditingValue.selection.extent); + editableTextState.bringIntoView( + editableTextState.textEditingValue.selection.extent, + ); } }, debugLabel: 'SpellCheckerSuggestionsToolbar.bringIntoView'); editableTextState.hideToolbar(); @@ -159,23 +174,24 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { return buttonItems.map((ContextMenuButtonItem buttonItem) { final TextSelectionToolbarTextButton button = TextSelectionToolbarTextButton( - padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), - onPressed: buttonItem.onPressed, - alignment: Alignment.centerLeft, - child: Text( - AdaptiveTextSelectionToolbar.getButtonLabel(context, buttonItem), - style: buttonItem.type == ContextMenuButtonType.delete - ? const TextStyle(color: Colors.blue) - : null, - ), - ); + padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), + onPressed: buttonItem.onPressed, + alignment: Alignment.centerLeft, + child: Text( + AdaptiveTextSelectionToolbar.getButtonLabel(context, buttonItem), + style: buttonItem.type == ContextMenuButtonType.delete + ? const TextStyle(color: Colors.blue) + : null, + ), + ); if (buttonItem.type != ContextMenuButtonType.delete) { return button; } return DecoratedBox( decoration: const BoxDecoration( - border: Border(top: BorderSide(color: Colors.grey))), + border: Border(top: BorderSide(color: Colors.grey)), + ), child: button, ); }).toList(); @@ -194,7 +210,8 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { final MediaQueryData mediaQueryData = MediaQuery.of(context); final double softKeyboardViewInsetsBottom = mediaQueryData.viewInsets.bottom; - final double paddingAbove = mediaQueryData.padding.top + + final double paddingAbove = + mediaQueryData.padding.top + CupertinoTextSelectionToolbar.kToolbarScreenPadding; // Makes up for the Padding. final Offset localAdjustment = Offset( @@ -212,7 +229,8 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { ), child: CustomSingleChildLayout( delegate: SpellCheckSuggestionsToolbarLayoutDelegate( - anchor: anchor - localAdjustment), + anchor: anchor - localAdjustment, + ), child: AnimatedSize( // This duration was eyeballed on a Pixel 2 emulator running Android // API 28 for the Material TextSelectionToolbar. @@ -230,8 +248,10 @@ class SpellCheckSuggestionsToolbar extends StatelessWidget { /// The Material-styled toolbar outline for the spell check suggestions /// toolbar. class _SpellCheckSuggestionsToolbarContainer extends StatelessWidget { - const _SpellCheckSuggestionsToolbarContainer( - {required this.height, required this.children}); + const _SpellCheckSuggestionsToolbarContainer({ + required this.height, + required this.children, + }); final double height; final List children; diff --git a/lib/common/widgets/text_field/system_context_menu.dart b/lib/common/widgets/text_field/system_context_menu.dart index 9969d01ae..827a8bc70 100644 --- a/lib/common/widgets/text_field/system_context_menu.dart +++ b/lib/common/widgets/text_field/system_context_menu.dart @@ -65,8 +65,9 @@ class SystemContextMenu extends StatefulWidget { }) { final ( startGlyphHeight: double startGlyphHeight, - endGlyphHeight: double endGlyphHeight - ) = editableTextState.getGlyphHeights(); + endGlyphHeight: double endGlyphHeight, + ) = editableTextState + .getGlyphHeights(); return SystemContextMenu._( key: key, @@ -123,7 +124,8 @@ class SystemContextMenu extends StatefulWidget { /// * [EditableTextState.contextMenuButtonItems], which provides the default /// [ContextMenuButtonItem]s for the Flutter-rendered context menu. static List getDefaultItems( - EditableTextState editableTextState) { + EditableTextState editableTextState, + ) { return [ if (editableTextState.copyEnabled) const IOSSystemContextMenuItemCopy(), if (editableTextState.cutEnabled) const IOSSystemContextMenuItemCut(), @@ -147,8 +149,9 @@ class _SystemContextMenuState extends State { @override void initState() { super.initState(); - _systemContextMenuController = - SystemContextMenuController(onSystemHide: widget.onSystemHide); + _systemContextMenuController = SystemContextMenuController( + onSystemHide: widget.onSystemHide, + ); } @override @@ -162,8 +165,9 @@ class _SystemContextMenuState extends State { assert(SystemContextMenu.isSupported(context)); if (widget.items.isNotEmpty) { - final WidgetsLocalizations localizations = - WidgetsLocalizations.of(context); + final WidgetsLocalizations localizations = WidgetsLocalizations.of( + context, + ); final List itemDatas = widget.items .map((IOSSystemContextMenuItem item) => item.getData(localizations)) .toList(); @@ -279,7 +283,8 @@ final class IOSSystemContextMenuItemPaste extends IOSSystemContextMenuItem { @override IOSSystemContextMenuItemDataPaste getData( - WidgetsLocalizations localizations) { + WidgetsLocalizations localizations, + ) { return const IOSSystemContextMenuItemDataPaste(); } } @@ -303,7 +308,8 @@ final class IOSSystemContextMenuItemSelectAll extends IOSSystemContextMenuItem { @override IOSSystemContextMenuItemDataSelectAll getData( - WidgetsLocalizations localizations) { + WidgetsLocalizations localizations, + ) { return const IOSSystemContextMenuItemDataSelectAll(); } } @@ -334,9 +340,11 @@ final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem { @override IOSSystemContextMenuItemDataLookUp getData( - WidgetsLocalizations localizations) { + WidgetsLocalizations localizations, + ) { return IOSSystemContextMenuItemDataLookUp( - title: title ?? localizations.lookUpButtonLabel); + title: title ?? localizations.lookUpButtonLabel, + ); } @override @@ -371,7 +379,8 @@ final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem { @override IOSSystemContextMenuItemDataSearchWeb getData( - WidgetsLocalizations localizations) { + WidgetsLocalizations localizations, + ) { return IOSSystemContextMenuItemDataSearchWeb( title: title ?? localizations.searchWebButtonLabel, ); @@ -409,9 +418,11 @@ final class IOSSystemContextMenuItemShare extends IOSSystemContextMenuItem { @override IOSSystemContextMenuItemDataShare getData( - WidgetsLocalizations localizations) { + WidgetsLocalizations localizations, + ) { return IOSSystemContextMenuItemDataShare( - title: title ?? localizations.shareButtonLabel); + title: title ?? localizations.shareButtonLabel, + ); } @override diff --git a/lib/common/widgets/text_field/text_field.dart b/lib/common/widgets/text_field/text_field.dart index 912172a37..c128d28f8 100644 --- a/lib/common/widgets/text_field/text_field.dart +++ b/lib/common/widgets/text_field/text_field.dart @@ -66,25 +66,27 @@ export 'package:flutter/services.dart' // late FocusNode myFocusNode; /// Signature for the [RichTextField.buildCounter] callback. -typedef InputCounterWidgetBuilder = Widget? Function( - /// The build context for the TextField. - BuildContext context, { - /// The length of the string currently in the input. - required int currentLength, +typedef InputCounterWidgetBuilder = + Widget? Function( + /// The build context for the TextField. + BuildContext context, { - /// The maximum string length that can be entered into the TextField. - required int? maxLength, + /// The length of the string currently in the input. + required int currentLength, - /// Whether or not the TextField is currently focused. Mainly provided for - /// the [liveRegion] parameter in the [Semantics] widget for accessibility. - required bool isFocused, -}); + /// The maximum string length that can be entered into the TextField. + required int? maxLength, + + /// Whether or not the TextField is currently focused. Mainly provided for + /// the [liveRegion] parameter in the [Semantics] widget for accessibility. + required bool isFocused, + }); class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDetectorBuilder { _TextFieldSelectionGestureDetectorBuilder({required RichTextFieldState state}) - : _state = state, - super(delegate: state); + : _state = state, + super(delegate: state); final RichTextFieldState _state; @@ -343,37 +345,44 @@ class RichTextField extends StatefulWidget { this.canRequestFocus = true, this.spellCheckConfiguration, this.magnifierConfiguration, - }) : assert(obscuringCharacter.length == 1), - smartDashesType = smartDashesType ?? - (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), - smartQuotesType = smartQuotesType ?? - (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), - assert(maxLines == null || maxLines > 0), - assert(minLines == null || minLines > 0), - assert( - (maxLines == null) || (minLines == null) || (maxLines >= minLines), - "minLines can't be greater than maxLines", - ), - assert( - !expands || (maxLines == null && minLines == null), - 'minLines and maxLines must be null when expands is true.', - ), - assert(!obscureText || maxLines == 1, - 'Obscured fields cannot be multiline.'), - assert(maxLength == null || - maxLength == RichTextField.noMaxLength || - maxLength > 0), - // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. - assert( - !identical(textInputAction, TextInputAction.newline) || - maxLines == 1 || - !identical(keyboardType, TextInputType.text), - 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', - ), - keyboardType = keyboardType ?? - (maxLines == 1 ? TextInputType.text : TextInputType.multiline), - enableInteractiveSelection = - enableInteractiveSelection ?? (!readOnly || !obscureText); + }) : assert(obscuringCharacter.length == 1), + smartDashesType = + smartDashesType ?? + (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), + smartQuotesType = + smartQuotesType ?? + (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), + assert(maxLines == null || maxLines > 0), + assert(minLines == null || minLines > 0), + assert( + (maxLines == null) || (minLines == null) || (maxLines >= minLines), + "minLines can't be greater than maxLines", + ), + assert( + !expands || (maxLines == null && minLines == null), + 'minLines and maxLines must be null when expands is true.', + ), + assert( + !obscureText || maxLines == 1, + 'Obscured fields cannot be multiline.', + ), + assert( + maxLength == null || + maxLength == RichTextField.noMaxLength || + maxLength > 0, + ), + // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. + assert( + !identical(textInputAction, TextInputAction.newline) || + maxLines == 1 || + !identical(keyboardType, TextInputType.text), + 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', + ), + keyboardType = + keyboardType ?? + (maxLines == 1 ? TextInputType.text : TextInputType.multiline), + enableInteractiveSelection = + enableInteractiveSelection ?? (!readOnly || !obscureText); /// The configuration for the magnifier of this text field. /// @@ -883,10 +892,12 @@ class RichTextField extends StatefulWidget { if (defaultTargetPlatform == TargetPlatform.iOS && SystemContextMenu.isSupported(context)) { return SystemContextMenu.editableText( - editableTextState: editableTextState); + editableTextState: editableTextState, + ); } return AdaptiveTextSelectionToolbar.editableText( - editableTextState: editableTextState); + editableTextState: editableTextState, + ); } /// {@macro flutter.widgets.EditableText.spellCheckConfiguration} @@ -936,7 +947,8 @@ class RichTextField extends StatefulWidget { case TargetPlatform.linux: case TargetPlatform.windows: return SpellCheckSuggestionsToolbar.editableText( - editableTextState: editableTextState); + editableTextState: editableTextState, + ); } } @@ -951,11 +963,12 @@ class RichTextField extends StatefulWidget { return const SpellCheckConfiguration.disabled(); } return configuration.copyWith( - misspelledTextStyle: configuration.misspelledTextStyle ?? + misspelledTextStyle: + configuration.misspelledTextStyle ?? RichTextField.materialMisspelledTextStyle, spellCheckSuggestionsToolbarBuilder: configuration.spellCheckSuggestionsToolbarBuilder ?? - RichTextField.defaultSpellCheckSuggestionsToolbarBuilder, + RichTextField.defaultSpellCheckSuggestionsToolbarBuilder, ); } @@ -967,11 +980,19 @@ class RichTextField extends StatefulWidget { super.debugFillProperties(properties); properties ..add( - DiagnosticsProperty('controller', controller, - defaultValue: null), + DiagnosticsProperty( + 'controller', + controller, + defaultValue: null, + ), + ) + ..add( + DiagnosticsProperty( + 'focusNode', + focusNode, + defaultValue: null, + ), ) - ..add(DiagnosticsProperty('focusNode', focusNode, - defaultValue: null)) ..add( DiagnosticsProperty( 'undoController', @@ -995,35 +1016,54 @@ class RichTextField extends StatefulWidget { ), ) ..add(DiagnosticsProperty('style', style, defaultValue: null)) - ..add(DiagnosticsProperty('autofocus', autofocus, - defaultValue: false)) ..add( - DiagnosticsProperty('obscuringCharacter', obscuringCharacter, - defaultValue: '•'), + DiagnosticsProperty('autofocus', autofocus, defaultValue: false), + ) + ..add( + DiagnosticsProperty( + 'obscuringCharacter', + obscuringCharacter, + defaultValue: '•', + ), + ) + ..add( + DiagnosticsProperty( + 'obscureText', + obscureText, + defaultValue: false, + ), + ) + ..add( + DiagnosticsProperty( + 'autocorrect', + autocorrect, + defaultValue: true, + ), ) - ..add(DiagnosticsProperty('obscureText', obscureText, - defaultValue: false)) - ..add(DiagnosticsProperty('autocorrect', autocorrect, - defaultValue: true)) ..add( EnumProperty( 'smartDashesType', smartDashesType, - defaultValue: - obscureText ? SmartDashesType.disabled : SmartDashesType.enabled, + defaultValue: obscureText + ? SmartDashesType.disabled + : SmartDashesType.enabled, ), ) ..add( EnumProperty( 'smartQuotesType', smartQuotesType, - defaultValue: - obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled, + defaultValue: obscureText + ? SmartQuotesType.disabled + : SmartQuotesType.enabled, ), ) ..add( - DiagnosticsProperty('enableSuggestions', enableSuggestions, - defaultValue: true), + DiagnosticsProperty( + 'enableSuggestions', + enableSuggestions, + defaultValue: true, + ), ) ..add(IntProperty('maxLines', maxLines, defaultValue: 1)) ..add(IntProperty('minLines', minLines, defaultValue: null)) @@ -1037,8 +1077,11 @@ class RichTextField extends StatefulWidget { ), ) ..add( - EnumProperty('textInputAction', textInputAction, - defaultValue: null), + EnumProperty( + 'textInputAction', + textInputAction, + defaultValue: null, + ), ) ..add( EnumProperty( @@ -1047,8 +1090,13 @@ class RichTextField extends StatefulWidget { defaultValue: TextCapitalization.none, ), ) - ..add(EnumProperty('textAlign', textAlign, - defaultValue: TextAlign.start)) + ..add( + EnumProperty( + 'textAlign', + textAlign, + defaultValue: TextAlign.start, + ), + ) ..add( DiagnosticsProperty( 'textAlignVertical', @@ -1056,24 +1104,39 @@ class RichTextField extends StatefulWidget { defaultValue: null, ), ) - ..add(EnumProperty('textDirection', textDirection, - defaultValue: null)) + ..add( + EnumProperty( + 'textDirection', + textDirection, + defaultValue: null, + ), + ) ..add(DoubleProperty('cursorWidth', cursorWidth, defaultValue: 2.0)) ..add(DoubleProperty('cursorHeight', cursorHeight, defaultValue: null)) - ..add(DiagnosticsProperty('cursorRadius', cursorRadius, - defaultValue: null)) + ..add( + DiagnosticsProperty( + 'cursorRadius', + cursorRadius, + defaultValue: null, + ), + ) ..add( DiagnosticsProperty( - 'cursorOpacityAnimates', cursorOpacityAnimates, - defaultValue: null), + 'cursorOpacityAnimates', + cursorOpacityAnimates, + defaultValue: null, + ), ) ..add(ColorProperty('cursorColor', cursorColor, defaultValue: null)) - ..add(ColorProperty('cursorErrorColor', cursorErrorColor, - defaultValue: null)) + ..add( + ColorProperty('cursorErrorColor', cursorErrorColor, defaultValue: null), + ) ..add( DiagnosticsProperty( - 'keyboardAppearance', keyboardAppearance, - defaultValue: null), + 'keyboardAppearance', + keyboardAppearance, + defaultValue: null, + ), ) ..add( DiagnosticsProperty( @@ -1105,16 +1168,25 @@ class RichTextField extends StatefulWidget { ), ) ..add( - DiagnosticsProperty('scrollPhysics', scrollPhysics, - defaultValue: null), + DiagnosticsProperty( + 'scrollPhysics', + scrollPhysics, + defaultValue: null, + ), ) ..add( - DiagnosticsProperty('clipBehavior', clipBehavior, - defaultValue: Clip.hardEdge), + DiagnosticsProperty( + 'clipBehavior', + clipBehavior, + defaultValue: Clip.hardEdge, + ), ) ..add( - DiagnosticsProperty('scribbleEnabled', scribbleEnabled, - defaultValue: true), + DiagnosticsProperty( + 'scribbleEnabled', + scribbleEnabled, + defaultValue: true, + ), ) ..add( DiagnosticsProperty( @@ -1163,7 +1235,8 @@ class RichTextFieldState extends State MaxLengthEnforcement get _effectiveMaxLengthEnforcement => widget.maxLengthEnforcement ?? LengthLimitingTextInputFormatter.getDefaultMaxLengthEnforcement( - Theme.of(context).platform); + Theme.of(context).platform, + ); bool _isHovering = false; @@ -1175,7 +1248,7 @@ class RichTextFieldState extends State bool _showSelectionHandles = false; late _TextFieldSelectionGestureDetectorBuilder - _selectionGestureDetectorBuilder; + _selectionGestureDetectorBuilder; // API for TextSelectionGestureDetectorBuilderDelegate. @override @@ -1197,13 +1270,12 @@ class RichTextFieldState extends State widget.maxLength != null && widget.maxLength! > 0 && ( - // widget.controller == null - // ? !restorePending && - // _effectiveController.value.text.characters.length > - // widget.maxLength! - // : - _effectiveController.value.text.characters.length > - widget.maxLength!); + // widget.controller == null + // ? !restorePending && + // _effectiveController.value.text.characters.length > + // widget.maxLength! + // : + _effectiveController.value.text.characters.length > widget.maxLength!); bool get _hasError => widget.decoration?.errorText != null || @@ -1216,8 +1288,9 @@ class RichTextFieldState extends State Theme.of(context).colorScheme.error; InputDecoration _getEffectiveDecoration() { - final MaterialLocalizations localizations = - MaterialLocalizations.of(context); + final MaterialLocalizations localizations = MaterialLocalizations.of( + context, + ); final ThemeData themeData = Theme.of(context); final InputDecoration effectiveDecoration = (widget.decoration ?? const InputDecoration()) @@ -1249,7 +1322,10 @@ class RichTextFieldState extends State // If buildCounter returns null, don't add a counter widget to the field. if (builtCounter != null) { counter = Semantics( - container: true, liveRegion: isFocused, child: builtCounter); + container: true, + liveRegion: isFocused, + child: builtCounter, + ); } return effectiveDecoration.copyWith(counter: counter); } @@ -1265,16 +1341,20 @@ class RichTextFieldState extends State if (widget.maxLength! > 0) { // Show the maxLength in the counter counterText += '/${widget.maxLength}'; - final int remaining = - (widget.maxLength! - currentLength).clamp(0, widget.maxLength!); - semanticCounterText = - localizations.remainingTextFieldCharacterCount(remaining); + final int remaining = (widget.maxLength! - currentLength).clamp( + 0, + widget.maxLength!, + ); + semanticCounterText = localizations.remainingTextFieldCharacterCount( + remaining, + ); } if (_hasIntrinsicError) { return effectiveDecoration.copyWith( errorText: effectiveDecoration.errorText ?? '', - counterStyle: effectiveDecoration.errorStyle ?? + counterStyle: + effectiveDecoration.errorStyle ?? (themeData.useMaterial3 ? _m3CounterErrorStyle(context) : _m2CounterErrorStyle(context)), @@ -1436,12 +1516,13 @@ class RichTextFieldState extends State // Rebuild the widget on focus change to show/hide the text selection // highlight. }); - _statesController.update( - WidgetState.focused, _effectiveFocusNode.hasFocus); + _statesController.update(WidgetState.focused, _effectiveFocusNode.hasFocus); } void _handleSelectionChanged( - TextSelection selection, SelectionChangedCause? cause) { + TextSelection selection, + SelectionChangedCause? cause, + ) { final bool willShowSelectionHandles = _shouldShowSelectionHandles(cause); if (willShowSelectionHandles != _showSelectionHandles) { setState(() { @@ -1508,8 +1589,7 @@ class RichTextFieldState extends State } _statesController.update(WidgetState.disabled, !_isEnabled); _statesController.update(WidgetState.hovered, _isHovering); - _statesController.update( - WidgetState.focused, _effectiveFocusNode.hasFocus); + _statesController.update(WidgetState.focused, _effectiveFocusNode.hasFocus); _statesController.update(WidgetState.error, _hasError); _statesController.addListener(_handleStatesControllerChange); } @@ -1524,8 +1604,9 @@ class RichTextFieldState extends State @override TextInputConfiguration get textInputConfiguration { - final List? autofillHints = - widget.autofillHints?.toList(growable: false); + final List? autofillHints = widget.autofillHints?.toList( + growable: false, + ); final AutofillConfiguration autofillConfiguration = autofillHints != null ? AutofillConfiguration( uniqueIdentifier: autofillId, @@ -1549,8 +1630,10 @@ class RichTextFieldState extends State : _m2StateInputStyle(context)!, _statesController.value, ); - final TextStyle providedStyle = - WidgetStateProperty.resolveAs(style, _statesController.value); + final TextStyle providedStyle = WidgetStateProperty.resolveAs( + style, + _statesController.value, + ); return providedStyle.merge(stateStyle); } @@ -1568,8 +1651,9 @@ class RichTextFieldState extends State ); final ThemeData theme = Theme.of(context); - final DefaultSelectionStyle selectionStyle = - DefaultSelectionStyle.of(context); + final DefaultSelectionStyle selectionStyle = DefaultSelectionStyle.of( + context, + ); final TextStyle? providedStyle = WidgetStateProperty.resolveAs( widget.style, _statesController.value, @@ -1601,16 +1685,16 @@ class RichTextFieldState extends State case TargetPlatform.macOS: spellCheckConfiguration = CupertinoRichTextField.inferIOSSpellCheckConfiguration( - widget.spellCheckConfiguration, - ); + widget.spellCheckConfiguration, + ); case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: spellCheckConfiguration = RichTextField.inferAndroidSpellCheckConfiguration( - widget.spellCheckConfiguration, - ); + widget.spellCheckConfiguration, + ); } TextSelectionControls? textSelectionControls = widget.selectionControls; @@ -1634,13 +1718,16 @@ class RichTextFieldState extends State cursorColor = _hasError ? _errorColor : widget.cursorColor ?? - selectionStyle.cursorColor ?? - cupertinoTheme.primaryColor; - selectionColor = selectionStyle.selectionColor ?? + selectionStyle.cursorColor ?? + cupertinoTheme.primaryColor; + selectionColor = + selectionStyle.selectionColor ?? cupertinoTheme.primaryColor.withOpacity(0.40); cursorRadius ??= const Radius.circular(2.0); cursorOffset = Offset( - iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context), 0); + iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context), + 0, + ); autocorrectionTextRectColor = selectionColor; case TargetPlatform.macOS: @@ -1652,13 +1739,16 @@ class RichTextFieldState extends State cursorColor = _hasError ? _errorColor : widget.cursorColor ?? - selectionStyle.cursorColor ?? - cupertinoTheme.primaryColor; - selectionColor = selectionStyle.selectionColor ?? + selectionStyle.cursorColor ?? + cupertinoTheme.primaryColor; + selectionColor = + selectionStyle.selectionColor ?? cupertinoTheme.primaryColor.withOpacity(0.40); cursorRadius ??= const Radius.circular(2.0); cursorOffset = Offset( - iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context), 0); + iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context), + 0, + ); handleDidGainAccessibilityFocus = () { // Automatically activate the TextField when it receives accessibility focus. if (!_effectiveFocusNode.hasFocus && @@ -1679,9 +1769,10 @@ class RichTextFieldState extends State cursorColor = _hasError ? _errorColor : widget.cursorColor ?? - selectionStyle.cursorColor ?? - theme.colorScheme.primary; - selectionColor = selectionStyle.selectionColor ?? + selectionStyle.cursorColor ?? + theme.colorScheme.primary; + selectionColor = + selectionStyle.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40); case TargetPlatform.linux: @@ -1692,9 +1783,10 @@ class RichTextFieldState extends State cursorColor = _hasError ? _errorColor : widget.cursorColor ?? - selectionStyle.cursorColor ?? - theme.colorScheme.primary; - selectionColor = selectionStyle.selectionColor ?? + selectionStyle.cursorColor ?? + theme.colorScheme.primary; + selectionColor = + selectionStyle.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40); handleDidGainAccessibilityFocus = () { // Automatically activate the TextField when it receives accessibility focus. @@ -1715,9 +1807,10 @@ class RichTextFieldState extends State cursorColor = _hasError ? _errorColor : widget.cursorColor ?? - selectionStyle.cursorColor ?? - theme.colorScheme.primary; - selectionColor = selectionStyle.selectionColor ?? + selectionStyle.cursorColor ?? + theme.colorScheme.primary; + selectionColor = + selectionStyle.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40); handleDidGainAccessibilityFocus = () { // Automatically activate the TextField when it receives accessibility focus. @@ -1762,8 +1855,9 @@ class RichTextFieldState extends State expands: widget.expands, // Only show the selection highlight when the text field is focused. selectionColor: focusNode.hasFocus ? selectionColor : null, - selectionControls: - widget.selectionEnabled ? textSelectionControls : null, + selectionControls: widget.selectionEnabled + ? textSelectionControls + : null, onChanged: widget.onChanged, onSelectionChanged: _handleSelectionChanged, onEditingComplete: widget.onEditingComplete, @@ -1802,7 +1896,8 @@ class RichTextFieldState extends State contentInsertionConfiguration: widget.contentInsertionConfiguration, contextMenuBuilder: widget.contextMenuBuilder, spellCheckConfiguration: spellCheckConfiguration, - magnifierConfiguration: widget.magnifierConfiguration ?? + magnifierConfiguration: + widget.magnifierConfiguration ?? TextMagnifier.adaptiveMagnifierConfiguration, ), ), @@ -1829,9 +1924,9 @@ class RichTextFieldState extends State } final MouseCursor effectiveMouseCursor = WidgetStateProperty.resolveAs( - widget.mouseCursor ?? WidgetStateMouseCursor.textable, - _statesController.value, - ); + widget.mouseCursor ?? WidgetStateMouseCursor.textable, + _statesController.value, + ); final int? semanticsMaxValueLength; if (_effectiveMaxLengthEnforcement != MaxLengthEnforcement.none && @@ -1862,8 +1957,8 @@ class RichTextFieldState extends State if (!_effectiveController.selection.isValid) { _effectiveController.selection = TextSelection.collapsed( - offset: _effectiveController.text.length, - ); + offset: _effectiveController.text.length, + ); } _requestKeyboard(); }, @@ -1926,10 +2021,9 @@ TextStyle? _m2StateInputStyle(BuildContext context) => return TextStyle(color: theme.textTheme.titleMedium?.color); }); -TextStyle _m2CounterErrorStyle(BuildContext context) => Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Theme.of(context).colorScheme.error); +TextStyle _m2CounterErrorStyle(BuildContext context) => Theme.of( + context, +).textTheme.bodySmall!.copyWith(color: Theme.of(context).colorScheme.error); // BEGIN GENERATED TOKEN PROPERTIES - TextField diff --git a/lib/common/widgets/text_field/text_selection.dart b/lib/common/widgets/text_field/text_selection.dart index ef149f913..b81a19bca 100644 --- a/lib/common/widgets/text_field/text_selection.dart +++ b/lib/common/widgets/text_field/text_selection.dart @@ -143,12 +143,13 @@ class TextSelectionGestureDetectorBuilder { ]) { assert(renderEditable.selection?.baseOffset != null); - final TextPosition tappedPosition = - renderEditable.getPositionForPoint(offset); + final TextPosition tappedPosition = renderEditable.getPositionForPoint( + offset, + ); final TextSelection selection = fromSelection ?? renderEditable.selection!; final bool baseIsCloser = (tappedPosition.offset - selection.baseOffset).abs() < - (tappedPosition.offset - selection.extentOffset).abs(); + (tappedPosition.offset - selection.extentOffset).abs(); final TextSelection nextSelection = selection.copyWith( baseOffset: baseIsCloser ? selection.extentOffset : selection.baseOffset, extentOffset: tappedPosition.offset, @@ -171,11 +172,13 @@ class TextSelectionGestureDetectorBuilder { void _extendSelection(Offset offset, SelectionChangedCause cause) { assert(renderEditable.selection?.baseOffset != null); - final TextPosition tappedPosition = - renderEditable.getPositionForPoint(offset); + final TextPosition tappedPosition = renderEditable.getPositionForPoint( + offset, + ); final TextSelection selection = renderEditable.selection!; - final TextSelection nextSelection = - selection.copyWith(extentOffset: tappedPosition.offset); + final TextSelection nextSelection = selection.copyWith( + extentOffset: tappedPosition.offset, + ); editableText.userUpdateTextEditingValue( editableText.textEditingValue.copyWith(selection: nextSelection), @@ -215,16 +218,16 @@ class TextSelectionGestureDetectorBuilder { double get _scrollPosition { final ScrollableState? scrollableState = delegate.editableTextKey.currentContext == null - ? null - : Scrollable.maybeOf(delegate.editableTextKey.currentContext!); + ? null + : Scrollable.maybeOf(delegate.editableTextKey.currentContext!); return scrollableState == null ? 0.0 : scrollableState.position.pixels; } AxisDirection? get _scrollDirection { final ScrollableState? scrollableState = delegate.editableTextKey.currentContext == null - ? null - : Scrollable.maybeOf(delegate.editableTextKey.currentContext!); + ? null + : Scrollable.maybeOf(delegate.editableTextKey.currentContext!); return scrollableState?.axisDirection; } @@ -249,11 +252,12 @@ class TextSelectionGestureDetectorBuilder { /// callback. @protected void onTapTrackStart() { - _isShiftPressed = HardwareKeyboard.instance.logicalKeysPressed - .intersection({ - LogicalKeyboardKey.shiftLeft, - LogicalKeyboardKey.shiftRight, - }).isNotEmpty; + _isShiftPressed = HardwareKeyboard.instance.logicalKeysPressed.intersection( + { + LogicalKeyboardKey.shiftLeft, + LogicalKeyboardKey.shiftRight, + }, + ).isNotEmpty; } /// Handler for [TextSelectionGestureDetector.onTapTrackReset]. @@ -287,8 +291,9 @@ class TextSelectionGestureDetectorBuilder { // vs [TapGestureRecognizer.onSecondaryTapUp] instead of having to track state in // renderEditable. When this migration is complete we should remove this hack. // See https://github.com/flutter/flutter/issues/115130. - renderEditable - .handleTapDown(TapDownDetails(globalPosition: details.globalPosition)); + renderEditable.handleTapDown( + TapDownDetails(globalPosition: details.globalPosition), + ); // The selection overlay should only be shown when the user is interacting // through a touch screen (via either a finger or a stylus). A mouse shouldn't // trigger the selection overlay. @@ -297,7 +302,8 @@ class TextSelectionGestureDetectorBuilder { // TODO(justinmc): Should a desktop platform show its selection toolbar when // receiving a tap event? Say a Windows device with a touchscreen. // https://github.com/flutter/flutter/issues/106586 - _shouldShowSelectionToolbar = kind == null || + _shouldShowSelectionToolbar = + kind == null || kind == PointerDeviceKind.touch || kind == PointerDeviceKind.stylus; @@ -309,8 +315,7 @@ class TextSelectionGestureDetectorBuilder { case TargetPlatform.android: if (editableText.widget.stylusHandwritingEnabled) { final bool stylusEnabled = switch (kind) { - PointerDeviceKind.stylus || - PointerDeviceKind.invertedStylus => + PointerDeviceKind.stylus || PointerDeviceKind.invertedStylus => editableText.widget.stylusHandwritingEnabled, _ => false, }; @@ -318,7 +323,8 @@ class TextSelectionGestureDetectorBuilder { Scribe.isFeatureAvailable().then((bool isAvailable) { if (isAvailable) { renderEditable.selectPosition( - cause: SelectionChangedCause.stylusHandwriting); + cause: SelectionChangedCause.stylusHandwriting, + ); Scribe.startStylusHandwriting(); } }); @@ -337,7 +343,10 @@ class TextSelectionGestureDetectorBuilder { ? null : const TextSelection.collapsed(offset: 0); _expandSelection( - details.globalPosition, SelectionChangedCause.tap, fromSelection); + details.globalPosition, + SelectionChangedCause.tap, + fromSelection, + ); return; } // On macOS, a tap/click places the selection in a precise position. @@ -474,7 +483,10 @@ class TextSelectionGestureDetectorBuilder { ? null : const TextSelection.collapsed(offset: 0); _expandSelection( - details.globalPosition, SelectionChangedCause.tap, fromSelection); + details.globalPosition, + SelectionChangedCause.tap, + fromSelection, + ); return; } switch (details.kind) { @@ -505,16 +517,19 @@ class TextSelectionGestureDetectorBuilder { // Selects the word edge closest to the tap when the editable is not focused, or if the tap was neither exclusively // or inclusively on `previousSelection`. If the selection remains the same after selecting the word edge, then we // toggle the toolbar, if the editable field is not read only. If the selection changes then we hide the toolbar. - final TextSelection previousSelection = renderEditable.selection ?? + final TextSelection previousSelection = + renderEditable.selection ?? editableText.textEditingValue.selection; - final TextPosition textPosition = - renderEditable.getPositionForPoint( - details.globalPosition, - ); + final TextPosition textPosition = renderEditable + .getPositionForPoint( + details.globalPosition, + ); final bool isAffinityTheSame = textPosition.affinity == previousSelection.affinity; - final bool wordAtCursorIndexIsMisspelled = editableText - .findSuggestionSpanAtCursorIndex(textPosition.offset) != + final bool wordAtCursorIndexIsMisspelled = + editableText.findSuggestionSpanAtCursorIndex( + textPosition.offset, + ) != null; if (wordAtCursorIndexIsMisspelled) { @@ -651,7 +666,8 @@ class TextSelectionGestureDetectorBuilder { case TargetPlatform.macOS: if (_longPressStartedWithoutFocus || renderEditable.readOnly) { renderEditable.selectWordsInRange( - from: details.globalPosition - + from: + details.globalPosition - details.offsetFromOrigin - editableOffset - scrollableOffset, @@ -675,7 +691,8 @@ class TextSelectionGestureDetectorBuilder { case TargetPlatform.linux: case TargetPlatform.windows: renderEditable.selectWordsInRange( - from: details.globalPosition - + from: + details.globalPosition - details.offsetFromOrigin - editableOffset - scrollableOffset, @@ -760,7 +777,8 @@ class TextSelectionGestureDetectorBuilder { // renderEditable. When this migration is complete we should remove this hack. // See https://github.com/flutter/flutter/issues/115130. renderEditable.handleSecondaryTapDown( - TapDownDetails(globalPosition: details.globalPosition)); + TapDownDetails(globalPosition: details.globalPosition), + ); _shouldShowSelectionToolbar = true; } @@ -785,37 +803,56 @@ class TextSelectionGestureDetectorBuilder { // Selects the set of paragraphs in a document that intersect a given range of // global positions. - void _selectParagraphsInRange( - {required Offset from, Offset? to, SelectionChangedCause? cause}) { - final TextBoundary paragraphBoundary = - ParagraphBoundary(editableText.textEditingValue.text); + void _selectParagraphsInRange({ + required Offset from, + Offset? to, + SelectionChangedCause? cause, + }) { + final TextBoundary paragraphBoundary = ParagraphBoundary( + editableText.textEditingValue.text, + ); _selectTextBoundariesInRange( - boundary: paragraphBoundary, from: from, to: to, cause: cause); + boundary: paragraphBoundary, + from: from, + to: to, + cause: cause, + ); } // Selects the set of lines in a document that intersect a given range of // global positions. - void _selectLinesInRange( - {required Offset from, Offset? to, SelectionChangedCause? cause}) { + void _selectLinesInRange({ + required Offset from, + Offset? to, + SelectionChangedCause? cause, + }) { final TextBoundary lineBoundary = LineBoundary(renderEditable); _selectTextBoundariesInRange( - boundary: lineBoundary, from: from, to: to, cause: cause); + boundary: lineBoundary, + from: from, + to: to, + cause: cause, + ); } // Returns the location of a text boundary at `extent`. When `extent` is at // the end of the text, returns the previous text boundary's location. TextRange _moveToTextBoundary( - TextPosition extent, TextBoundary textBoundary) { + TextPosition extent, + TextBoundary textBoundary, + ) { assert(extent.offset >= 0); // Use extent.offset - 1 when `extent` is at the end of the text to retrieve // the previous text boundary's location. - final int start = textBoundary.getLeadingTextBoundaryAt( + final int start = + textBoundary.getLeadingTextBoundaryAt( extent.offset == editableText.textEditingValue.text.length ? extent.offset - 1 : extent.offset, ) ?? 0; - final int end = textBoundary.getTrailingTextBoundaryAt(extent.offset) ?? + final int end = + textBoundary.getTrailingTextBoundaryAt(extent.offset) ?? editableText.textEditingValue.text.length; return TextRange(start: start, end: end); } @@ -836,8 +873,9 @@ class TextSelectionGestureDetectorBuilder { }) { final TextPosition fromPosition = renderEditable.getPositionForPoint(from); final TextRange fromRange = _moveToTextBoundary(fromPosition, boundary); - final TextPosition toPosition = - to == null ? fromPosition : renderEditable.getPositionForPoint(to); + final TextPosition toPosition = to == null + ? fromPosition + : renderEditable.getPositionForPoint(to); final TextRange toRange = toPosition == fromPosition ? fromRange : _moveToTextBoundary(toPosition, boundary); @@ -878,10 +916,14 @@ class TextSelectionGestureDetectorBuilder { case TargetPlatform.macOS: case TargetPlatform.windows: _selectParagraphsInRange( - from: details.globalPosition, cause: SelectionChangedCause.tap); + from: details.globalPosition, + cause: SelectionChangedCause.tap, + ); case TargetPlatform.linux: _selectLinesInRange( - from: details.globalPosition, cause: SelectionChangedCause.tap); + from: details.globalPosition, + cause: SelectionChangedCause.tap, + ); } } if (shouldShowSelectionToolbar) { @@ -903,7 +945,8 @@ class TextSelectionGestureDetectorBuilder { return; } final PointerDeviceKind? kind = details.kind; - _shouldShowSelectionToolbar = kind == null || + _shouldShowSelectionToolbar = + kind == null || kind == PointerDeviceKind.touch || kind == PointerDeviceKind.stylus; @@ -1003,12 +1046,16 @@ class TextSelectionGestureDetectorBuilder { final Offset editableOffset = renderEditable.maxLines == 1 ? Offset(renderEditable.offset.pixels - _dragStartViewportOffset, 0.0) : Offset( - 0.0, renderEditable.offset.pixels - _dragStartViewportOffset); + 0.0, + renderEditable.offset.pixels - _dragStartViewportOffset, + ); final Offset scrollableOffset = switch (axisDirectionToAxis( _scrollDirection ?? AxisDirection.left, )) { - Axis.horizontal => - Offset(_scrollPosition - _dragStartScrollOffset, 0.0), + Axis.horizontal => Offset( + _scrollPosition - _dragStartScrollOffset, + 0.0, + ), Axis.vertical => Offset(0.0, _scrollPosition - _dragStartScrollOffset), }; final Offset dragStartGlobalPosition = @@ -1051,7 +1098,8 @@ class TextSelectionGestureDetectorBuilder { case PointerDeviceKind.mouse: case PointerDeviceKind.trackpad: return _selectParagraphsInRange( - from: dragStartGlobalPosition - + from: + dragStartGlobalPosition - editableOffset - scrollableOffset, to: details.globalPosition, @@ -1130,7 +1178,8 @@ class TextSelectionGestureDetectorBuilder { cause: SelectionChangedCause.drag, ); return _showMagnifierIfSupportedByPlatform( - details.globalPosition); + details.globalPosition, + ); } case null: break; @@ -1151,14 +1200,17 @@ class TextSelectionGestureDetectorBuilder { (defaultTargetPlatform != TargetPlatform.iOS && defaultTargetPlatform != TargetPlatform.macOS)) { return _extendSelection( - details.globalPosition, SelectionChangedCause.drag); + details.globalPosition, + SelectionChangedCause.drag, + ); } // If the drag inverts the selection, Mac and iOS revert to the initial // selection. final TextSelection selection = editableText.textEditingValue.selection; - final TextPosition nextExtent = - renderEditable.getPositionForPoint(details.globalPosition); + final TextPosition nextExtent = renderEditable.getPositionForPoint( + details.globalPosition, + ); final bool isShiftTapDragSelectionForward = _dragStartSelection!.baseOffset < _dragStartSelection!.extentOffset; final bool isInverted = isShiftTapDragSelectionForward @@ -1223,8 +1275,11 @@ class TextSelectionGestureDetectorBuilder { /// The [child] or its subtree should contain an [EditableText] whose key is /// the [GlobalKey] provided by the [delegate]'s /// [TextSelectionGestureDetectorBuilderDelegate.editableTextKey]. - Widget buildGestureDetector( - {Key? key, HitTestBehavior? behavior, required Widget child}) { + Widget buildGestureDetector({ + Key? key, + HitTestBehavior? behavior, + required Widget child, + }) { return TextSelectionGestureDetector( key: key, onTapTrackStart: onTapTrackStart, @@ -1375,30 +1430,30 @@ class _TextSelectionGestureDetectorState gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers( - () => TapGestureRecognizer(debugOwner: this), - (TapGestureRecognizer instance) { - instance - ..onSecondaryTap = widget.onSecondaryTap - ..onSecondaryTapDown = widget.onSecondaryTapDown; - }, - ); + () => TapGestureRecognizer(debugOwner: this), + (TapGestureRecognizer instance) { + instance + ..onSecondaryTap = widget.onSecondaryTap + ..onSecondaryTapDown = widget.onSecondaryTapDown; + }, + ); if (widget.onSingleLongTapStart != null || widget.onSingleLongTapMoveUpdate != null || widget.onSingleLongTapEnd != null) { gestures[LongPressGestureRecognizer] = GestureRecognizerFactoryWithHandlers( - () => LongPressGestureRecognizer( - debugOwner: this, - supportedDevices: {PointerDeviceKind.touch}, - ), - (LongPressGestureRecognizer instance) { - instance - ..onLongPressStart = _handleLongPressStart - ..onLongPressMoveUpdate = _handleLongPressMoveUpdate - ..onLongPressEnd = _handleLongPressEnd; - }, - ); + () => LongPressGestureRecognizer( + debugOwner: this, + supportedDevices: {PointerDeviceKind.touch}, + ), + (LongPressGestureRecognizer instance) { + instance + ..onLongPressStart = _handleLongPressStart + ..onLongPressMoveUpdate = _handleLongPressMoveUpdate + ..onLongPressEnd = _handleLongPressEnd; + }, + ); } if (widget.onDragSelectionStart != null || @@ -1410,60 +1465,64 @@ class _TextSelectionGestureDetectorState case TargetPlatform.iOS: gestures[TapAndHorizontalDragGestureRecognizer] = GestureRecognizerFactoryWithHandlers< - TapAndHorizontalDragGestureRecognizer>( - () => TapAndHorizontalDragGestureRecognizer(debugOwner: this), - (TapAndHorizontalDragGestureRecognizer instance) { - instance - // Text selection should start from the position of the first pointer - // down event. - ..dragStartBehavior = DragStartBehavior.down - ..eagerVictoryOnDrag = - defaultTargetPlatform != TargetPlatform.iOS - ..onTapTrackStart = _handleTapTrackStart - ..onTapTrackReset = _handleTapTrackReset - ..onTapDown = _handleTapDown - ..onDragStart = _handleDragStart - ..onDragUpdate = _handleDragUpdate - ..onDragEnd = _handleDragEnd - ..onTapUp = _handleTapUp - ..onCancel = _handleTapCancel; - }, - ); + TapAndHorizontalDragGestureRecognizer + >( + () => TapAndHorizontalDragGestureRecognizer(debugOwner: this), + (TapAndHorizontalDragGestureRecognizer instance) { + instance + // Text selection should start from the position of the first pointer + // down event. + ..dragStartBehavior = DragStartBehavior.down + ..eagerVictoryOnDrag = + defaultTargetPlatform != TargetPlatform.iOS + ..onTapTrackStart = _handleTapTrackStart + ..onTapTrackReset = _handleTapTrackReset + ..onTapDown = _handleTapDown + ..onDragStart = _handleDragStart + ..onDragUpdate = _handleDragUpdate + ..onDragEnd = _handleDragEnd + ..onTapUp = _handleTapUp + ..onCancel = _handleTapCancel; + }, + ); case TargetPlatform.linux: case TargetPlatform.macOS: case TargetPlatform.windows: gestures[TapAndPanGestureRecognizer] = GestureRecognizerFactoryWithHandlers( - () => TapAndPanGestureRecognizer(debugOwner: this), - (TapAndPanGestureRecognizer instance) { - instance - // Text selection should start from the position of the first pointer - // down event. - ..dragStartBehavior = DragStartBehavior.down - ..onTapTrackStart = _handleTapTrackStart - ..onTapTrackReset = _handleTapTrackReset - ..onTapDown = _handleTapDown - ..onDragStart = _handleDragStart - ..onDragUpdate = _handleDragUpdate - ..onDragEnd = _handleDragEnd - ..onTapUp = _handleTapUp - ..onCancel = _handleTapCancel; - }, - ); + () => TapAndPanGestureRecognizer(debugOwner: this), + (TapAndPanGestureRecognizer instance) { + instance + // Text selection should start from the position of the first pointer + // down event. + ..dragStartBehavior = DragStartBehavior.down + ..onTapTrackStart = _handleTapTrackStart + ..onTapTrackReset = _handleTapTrackReset + ..onTapDown = _handleTapDown + ..onDragStart = _handleDragStart + ..onDragUpdate = _handleDragUpdate + ..onDragEnd = _handleDragEnd + ..onTapUp = _handleTapUp + ..onCancel = _handleTapCancel; + }, + ); } } if (widget.onForcePressStart != null || widget.onForcePressEnd != null) { gestures[ForcePressGestureRecognizer] = GestureRecognizerFactoryWithHandlers( - () => ForcePressGestureRecognizer(debugOwner: this), - (ForcePressGestureRecognizer instance) { - instance - ..onStart = - widget.onForcePressStart != null ? _forcePressStarted : null - ..onEnd = widget.onForcePressEnd != null ? _forcePressEnded : null; - }, - ); + () => ForcePressGestureRecognizer(debugOwner: this), + (ForcePressGestureRecognizer instance) { + instance + ..onStart = widget.onForcePressStart != null + ? _forcePressStarted + : null + ..onEnd = widget.onForcePressEnd != null + ? _forcePressEnded + : null; + }, + ); } return RawGestureDetector( @@ -1502,13 +1561,15 @@ class TextSelectionOverlay { this.contextMenuBuilder, required TextMagnifierConfiguration magnifierConfiguration, required this.controller, - }) : _handlesVisible = handlesVisible, - _value = value { + }) : _handlesVisible = handlesVisible, + _value = value { assert(debugMaybeDispatchCreated('widgets', 'TextSelectionOverlay', this)); - renderObject.selectionStartInViewport - .addListener(_updateTextSelectionOverlayVisibilities); - renderObject.selectionEndInViewport - .addListener(_updateTextSelectionOverlayVisibilities); + renderObject.selectionStartInViewport.addListener( + _updateTextSelectionOverlayVisibilities, + ); + renderObject.selectionEndInViewport.addListener( + _updateTextSelectionOverlayVisibilities, + ); _updateTextSelectionOverlayVisibilities(); _selectionOverlay = SelectionOverlay( magnifierConfiguration: magnifierConfiguration, @@ -1579,10 +1640,12 @@ class TextSelectionOverlay { final ValueNotifier _effectiveStartHandleVisibility = ValueNotifier(false); - final ValueNotifier _effectiveEndHandleVisibility = - ValueNotifier(false); - final ValueNotifier _effectiveToolbarVisibility = - ValueNotifier(false); + final ValueNotifier _effectiveEndHandleVisibility = ValueNotifier( + false, + ); + final ValueNotifier _effectiveToolbarVisibility = ValueNotifier( + false, + ); void _updateTextSelectionOverlayVisibilities() { _effectiveStartHandleVisibility.value = @@ -1591,7 +1654,7 @@ class TextSelectionOverlay { _handlesVisible && renderObject.selectionEndInViewport.value; _effectiveToolbarVisibility.value = renderObject.selectionStartInViewport.value || - renderObject.selectionEndInViewport.value; + renderObject.selectionEndInViewport.value; } /// Whether selection handles are visible. @@ -1635,14 +1698,17 @@ class TextSelectionOverlay { assert(context.mounted); _selectionOverlay.showToolbar( - context: context, contextMenuBuilder: contextMenuBuilder); + context: context, + contextMenuBuilder: contextMenuBuilder, + ); return; } /// Shows toolbar with spell check suggestions of misspelled words that are /// available for click-and-replace. void showSpellCheckSuggestionsToolbar( - WidgetBuilder spellCheckSuggestionsToolbarBuilder) { + WidgetBuilder spellCheckSuggestionsToolbarBuilder, + ) { _updateSelectionOverlay(); assert(context.mounted); _selectionOverlay.showSpellCheckSuggestionsToolbar( @@ -1654,8 +1720,9 @@ class TextSelectionOverlay { /// {@macro flutter.widgets.SelectionOverlay.showMagnifier} void showMagnifier(Offset positionToShow) { - final TextPosition position = - renderObject.getPositionForPoint(positionToShow); + final TextPosition position = renderObject.getPositionForPoint( + positionToShow, + ); _updateSelectionOverlay(); _selectionOverlay.showMagnifier( _buildMagnifier( @@ -1668,8 +1735,9 @@ class TextSelectionOverlay { /// {@macro flutter.widgets.SelectionOverlay.updateMagnifier} void updateMagnifier(Offset positionToShow) { - final TextPosition position = - renderObject.getPositionForPoint(positionToShow); + final TextPosition position = renderObject.getPositionForPoint( + positionToShow, + ); _updateSelectionOverlay(); _selectionOverlay.updateMagnifier( _buildMagnifier( @@ -1772,10 +1840,12 @@ class TextSelectionOverlay { void dispose() { assert(debugMaybeDispatchDisposed(this)); _selectionOverlay.dispose(); - renderObject.selectionStartInViewport - .removeListener(_updateTextSelectionOverlayVisibilities); - renderObject.selectionEndInViewport - .removeListener(_updateTextSelectionOverlayVisibilities); + renderObject.selectionStartInViewport.removeListener( + _updateTextSelectionOverlayVisibilities, + ); + renderObject.selectionEndInViewport.removeListener( + _updateTextSelectionOverlayVisibilities, + ); _effectiveToolbarVisibility.dispose(); _effectiveStartHandleVisibility.dispose(); _effectiveEndHandleVisibility.dispose(); @@ -1800,8 +1870,9 @@ class TextSelectionOverlay { firstSelectedGraphemeExtent = selectedGraphemes.characters.first.length; startHandleRect = renderObject.getRectForComposingRange( TextRange( - start: _selection.start, - end: _selection.start + firstSelectedGraphemeExtent), + start: _selection.start, + end: _selection.start + firstSelectedGraphemeExtent, + ), ); } return startHandleRect?.height ?? renderObject.preferredLineHeight; @@ -1819,8 +1890,9 @@ class TextSelectionOverlay { lastSelectedGraphemeExtent = selectedGraphemes.characters.last.length; endHandleRect = renderObject.getRectForComposingRange( TextRange( - start: _selection.end - lastSelectedGraphemeExtent, - end: _selection.end), + start: _selection.end - lastSelectedGraphemeExtent, + end: _selection.end, + ), ); } return endHandleRect?.height ?? renderObject.preferredLineHeight; @@ -1831,41 +1903,48 @@ class TextSelectionOverlay { required Offset globalGesturePosition, required TextPosition currentTextPosition, }) { - final TextSelection lineAtOffset = - renderEditable.getLineAtOffset(currentTextPosition); + final TextSelection lineAtOffset = renderEditable.getLineAtOffset( + currentTextPosition, + ); final TextPosition positionAtEndOfLine = TextPosition( offset: lineAtOffset.extentOffset, affinity: TextAffinity.upstream, ); // Default affinity is downstream. - final TextPosition positionAtBeginningOfLine = - TextPosition(offset: lineAtOffset.baseOffset); + final TextPosition positionAtBeginningOfLine = TextPosition( + offset: lineAtOffset.baseOffset, + ); final Rect localLineBoundaries = Rect.fromPoints( renderEditable.getLocalRectForCaret(positionAtBeginningOfLine).topCenter, renderEditable.getLocalRectForCaret(positionAtEndOfLine).bottomCenter, ); - final RenderBox? overlay = Overlay.of(context, rootOverlay: true) - .context - .findRenderObject() as RenderBox?; + final RenderBox? overlay = + Overlay.of(context, rootOverlay: true).context.findRenderObject() + as RenderBox?; final Matrix4 transformToOverlay = renderEditable.getTransformTo(overlay); final Rect overlayLineBoundaries = MatrixUtils.transformRect( transformToOverlay, localLineBoundaries, ); - final Rect localCaretRect = - renderEditable.getLocalRectForCaret(currentTextPosition); - final Rect overlayCaretRect = - MatrixUtils.transformRect(transformToOverlay, localCaretRect); + final Rect localCaretRect = renderEditable.getLocalRectForCaret( + currentTextPosition, + ); + final Rect overlayCaretRect = MatrixUtils.transformRect( + transformToOverlay, + localCaretRect, + ); final Offset overlayGesturePosition = overlay?.globalToLocal(globalGesturePosition) ?? globalGesturePosition; return MagnifierInfo( fieldBounds: MatrixUtils.transformRect( - transformToOverlay, renderEditable.paintBounds), + transformToOverlay, + renderEditable.paintBounds, + ), globalGesturePosition: overlayGesturePosition, caretRect: overlayCaretRect, currentLineBoundaries: overlayLineBoundaries, @@ -1894,9 +1973,10 @@ class TextSelectionOverlay { // scale transformation, the line height will also be scaled. final double centerOfLineLocal = _selectionOverlay.selectionEndpoints.last.point.dy - - renderObject.preferredLineHeight / 2; - final double centerOfLineGlobal = - renderObject.localToGlobal(Offset(0.0, centerOfLineLocal)).dy; + renderObject.preferredLineHeight / 2; + final double centerOfLineGlobal = renderObject + .localToGlobal(Offset(0.0, centerOfLineLocal)) + .dy; _endHandleDragTarget = centerOfLineGlobal - details.globalPosition.dy; // Instead of finding the TextPosition at the handle's location directly, // use the vertical center of the line that it points to. This is because @@ -1936,7 +2016,8 @@ class TextSelectionOverlay { double _getHandleDy(double dragDy, double handleDy) { final double distanceDragged = dragDy - handleDy; final int dragDirection = distanceDragged < 0.0 ? -1 : 1; - final int linesDragged = dragDirection * + final int linesDragged = + dragDirection * (distanceDragged.abs() / renderObject.preferredLineHeight).floor(); return handleDy + linesDragged * renderObject.preferredLineHeight; } @@ -1949,8 +2030,9 @@ class TextSelectionOverlay { // This is NOT the same as details.localPosition. That is relative to the // selection handle, whereas this is relative to the RenderEditable. - final Offset localPosition = - renderObject.globalToLocal(details.globalPosition); + final Offset localPosition = renderObject.globalToLocal( + details.globalPosition, + ); final double nextEndHandleDragPositionLocal = _getHandleDy( localPosition.dy, @@ -1965,8 +2047,9 @@ class TextSelectionOverlay { _endHandleDragPosition + _endHandleDragTarget, ); - TextPosition position = - renderObject.getPositionForPoint(handleTargetGlobal); + TextPosition position = renderObject.getPositionForPoint( + handleTargetGlobal, + ); // bggRGjQaUbCoE right drag position = controller.dragOffset(position); @@ -1980,8 +2063,9 @@ class TextSelectionOverlay { ), ); - final TextSelection currentSelection = - TextSelection.fromPosition(position); + final TextSelection currentSelection = TextSelection.fromPosition( + position, + ); _handleSelectionHandleChanged(currentSelection); return; } @@ -1995,7 +2079,7 @@ class TextSelectionOverlay { // always returns true for a TextSelection. final bool dragStartSelectionNormalized = _dragStartSelection!.extentOffset >= - _dragStartSelection!.baseOffset; + _dragStartSelection!.baseOffset; newSelection = TextSelection( baseOffset: dragStartSelectionNormalized ? _dragStartSelection!.baseOffset @@ -2045,9 +2129,10 @@ class TextSelectionOverlay { // scale transformation, the line height will also be scaled. final double centerOfLineLocal = _selectionOverlay.selectionEndpoints.first.point.dy - - renderObject.preferredLineHeight / 2; - final double centerOfLineGlobal = - renderObject.localToGlobal(Offset(0.0, centerOfLineLocal)).dy; + renderObject.preferredLineHeight / 2; + final double centerOfLineGlobal = renderObject + .localToGlobal(Offset(0.0, centerOfLineLocal)) + .dy; _startHandleDragTarget = centerOfLineGlobal - details.globalPosition.dy; // Instead of finding the TextPosition at the handle's location directly, // use the vertical center of the line that it points to. This is because @@ -2075,8 +2160,9 @@ class TextSelectionOverlay { // This is NOT the same as details.localPosition. That is relative to the // selection handle, whereas this is relative to the RenderEditable. - final Offset localPosition = - renderObject.globalToLocal(details.globalPosition); + final Offset localPosition = renderObject.globalToLocal( + details.globalPosition, + ); final double nextStartHandleDragPositionLocal = _getHandleDy( localPosition.dy, renderObject.globalToLocal(Offset(0.0, _startHandleDragPosition)).dy, @@ -2088,8 +2174,9 @@ class TextSelectionOverlay { details.globalPosition.dx, _startHandleDragPosition + _startHandleDragTarget, ); - TextPosition position = - renderObject.getPositionForPoint(handleTargetGlobal); + TextPosition position = renderObject.getPositionForPoint( + handleTargetGlobal, + ); // bggRGjQaUbCoE single drag, left drag position = controller.dragOffset(position); @@ -2103,8 +2190,9 @@ class TextSelectionOverlay { ), ); - final TextSelection currentSelection = - TextSelection.fromPosition(position); + final TextSelection currentSelection = TextSelection.fromPosition( + position, + ); _handleSelectionHandleChanged(currentSelection); return; } @@ -2118,7 +2206,7 @@ class TextSelectionOverlay { // always returns true for a TextSelection. final bool dragStartSelectionNormalized = _dragStartSelection!.extentOffset >= - _dragStartSelection!.baseOffset; + _dragStartSelection!.baseOffset; newSelection = TextSelection( baseOffset: dragStartSelectionNormalized ? _dragStartSelection!.extentOffset @@ -2142,8 +2230,8 @@ class TextSelectionOverlay { _buildMagnifier( currentTextPosition: newSelection.extent.offset < newSelection.base.offset - ? newSelection.extent - : newSelection.base, + ? newSelection.extent + : newSelection.base, globalGesturePosition: details.globalPosition, renderEditable: renderObject, ), @@ -2167,7 +2255,9 @@ class TextSelectionOverlay { _selectionOverlay.hideMagnifier(); if (!_selection.isCollapsed) { _selectionOverlay.showToolbar( - context: context, contextMenuBuilder: contextMenuBuilder); + context: context, + contextMenuBuilder: contextMenuBuilder, + ); } } @@ -2237,13 +2327,13 @@ class SelectionOverlay { ) Offset? toolbarLocation, this.magnifierConfiguration = TextMagnifierConfiguration.disabled, - }) : _startHandleType = startHandleType, - _lineHeightAtStart = lineHeightAtStart, - _endHandleType = endHandleType, - _lineHeightAtEnd = lineHeightAtEnd, - _selectionEndpoints = selectionEndpoints, - _toolbarLocation = toolbarLocation, - assert(debugCheckHasOverlay(context)) { + }) : _startHandleType = startHandleType, + _lineHeightAtStart = lineHeightAtStart, + _endHandleType = endHandleType, + _lineHeightAtEnd = lineHeightAtEnd, + _selectionEndpoints = selectionEndpoints, + _toolbarLocation = toolbarLocation, + assert(debugCheckHasOverlay(context)) { assert(debugMaybeDispatchCreated('widgets', 'SelectionOverlay', this)); } @@ -2252,8 +2342,8 @@ class SelectionOverlay { final ValueNotifier _magnifierInfo = ValueNotifier( - MagnifierInfo.empty, - ); + MagnifierInfo.empty, + ); // [MagnifierController.show] and [MagnifierController.hide] should not be // called directly, except from inside [showMagnifier] and [hideMagnifier]. If @@ -2719,8 +2809,10 @@ class SelectionOverlay { /// Shows toolbar with spell check suggestions of misspelled words that are /// available for click-and-replace. - void showSpellCheckSuggestionsToolbar( - {BuildContext? context, required WidgetBuilder builder}) { + void showSpellCheckSuggestionsToolbar({ + BuildContext? context, + required WidgetBuilder builder, + }) { if (context == null) { return; } @@ -2890,15 +2982,15 @@ class SelectionOverlay { final bool isMultiline = selectionEndpoints.last.point.dy - selectionEndpoints.first.point.dy > - lineHeightAtEnd / 2; + lineHeightAtEnd / 2; // If the selected text spans more than 1 line, horizontally center the toolbar. // Derived from both iOS and Android. final double midX = isMultiline ? editingRegion.width / 2 : (selectionEndpoints.first.point.dx + - selectionEndpoints.last.point.dx) / - 2; + selectionEndpoints.last.point.dx) / + 2; final Offset midpoint = Offset( midX, @@ -2980,7 +3072,9 @@ class _SelectionToolbarWrapperState extends State<_SelectionToolbarWrapper> super.initState(); _controller = AnimationController( - duration: SelectionOverlay.fadeDuration, vsync: this); + duration: SelectionOverlay.fadeDuration, + vsync: this, + ); _toolbarVisibilityChanged(); widget.visibility?.addListener(_toolbarVisibilityChanged); @@ -3073,7 +3167,9 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> super.initState(); _controller = AnimationController( - duration: SelectionOverlay.fadeDuration, vsync: this); + duration: SelectionOverlay.fadeDuration, + vsync: this, + ); _handleVisibilityChanged(); widget.visibility?.addListener(_handleVisibilityChanged); @@ -3094,9 +3190,12 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> /// interactive area should be at least [kMinInteractiveDimension] square, /// which this method does not consider. Rect _getHandleRect( - TextSelectionHandleType type, double preferredLineHeight) { - final Size handleSize = - widget.selectionControls.getHandleSize(preferredLineHeight); + TextSelectionHandleType type, + double preferredLineHeight, + ) { + final Size handleSize = widget.selectionControls.getHandleSize( + preferredLineHeight, + ); return Rect.fromLTWH(0.0, 0.0, handleSize.width, handleSize.height); } @@ -3117,13 +3216,17 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> @override Widget build(BuildContext context) { - final Rect handleRect = - _getHandleRect(widget.type, widget.preferredLineHeight); + final Rect handleRect = _getHandleRect( + widget.type, + widget.preferredLineHeight, + ); // Make sure the GestureDetector is big enough to be easily interactive. final Rect interactiveRect = handleRect.expandToInclude( Rect.fromCircle( - center: handleRect.center, radius: kMinInteractiveDimension / 2), + center: handleRect.center, + radius: kMinInteractiveDimension / 2, + ), ); final RelativeRect padding = RelativeRect.fromLTRB( math.max((interactiveRect.width - handleRect.width) / 2, 0), @@ -3142,7 +3245,7 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> // other drag gestures. final bool eagerlyAcceptDragWhenCollapsed = widget.type == TextSelectionHandleType.collapsed && - defaultTargetPlatform == TargetPlatform.iOS; + defaultTargetPlatform == TargetPlatform.iOS; return CompositedTransformFollower( link: widget.handleLayerLink, @@ -3161,26 +3264,26 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> gestures: { PanGestureRecognizer: GestureRecognizerFactoryWithHandlers( - () => PanGestureRecognizer( - debugOwner: this, - // Mouse events select the text and do not drag the cursor. - supportedDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.stylus, - PointerDeviceKind.unknown, - }, - ), - (PanGestureRecognizer instance) { - instance - ..dragStartBehavior = widget.dragStartBehavior - ..gestureSettings = eagerlyAcceptDragWhenCollapsed - ? const DeviceGestureSettings(touchSlop: 1.0) - : null - ..onStart = widget.onSelectionHandleDragStart - ..onUpdate = widget.onSelectionHandleDragUpdate - ..onEnd = widget.onSelectionHandleDragEnd; - }, - ), + () => PanGestureRecognizer( + debugOwner: this, + // Mouse events select the text and do not drag the cursor. + supportedDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.stylus, + PointerDeviceKind.unknown, + }, + ), + (PanGestureRecognizer instance) { + instance + ..dragStartBehavior = widget.dragStartBehavior + ..gestureSettings = eagerlyAcceptDragWhenCollapsed + ? const DeviceGestureSettings(touchSlop: 1.0) + : null + ..onStart = widget.onSelectionHandleDragStart + ..onUpdate = widget.onSelectionHandleDragUpdate + ..onEnd = widget.onSelectionHandleDragEnd; + }, + ), }, child: Padding( padding: EdgeInsets.only( diff --git a/lib/common/widgets/video_card/video_card_h.dart b/lib/common/widgets/video_card/video_card_h.dart index 0d7ce79cf..56a408da1 100644 --- a/lib/common/widgets/video_card/video_card_h.dart +++ b/lib/common/widgets/video_card/video_card_h.dart @@ -60,13 +60,15 @@ class VideoCardH extends StatelessWidget { clipBehavior: Clip.none, children: [ InkWell( - onLongPress: onLongPress ?? + onLongPress: + onLongPress ?? () => imageSaveDialog( - bvid: videoItem.bvid, - title: videoItem.title, - cover: videoItem.cover, - ), - onTap: onTap ?? + bvid: videoItem.bvid, + title: videoItem.title, + cover: videoItem.cover, + ), + onTap: + onTap ?? () async { if (type == 'ketang') { SmartDialog.showToast('课堂视频暂不支持播放'); @@ -79,7 +81,8 @@ class VideoCardH extends StatelessWidget { } } else { SmartDialog.showToast( - 'err: live_room : ${videoItem.runtimeType}'); + 'err: live_room : ${videoItem.runtimeType}', + ); } return; } @@ -90,15 +93,18 @@ class VideoCardH extends StatelessWidget { } } try { - final int? cid = videoItem.cid ?? + final int? cid = + videoItem.cid ?? await SearchHttp.ab2c( - aid: videoItem.aid, bvid: videoItem.bvid); + aid: videoItem.aid, + bvid: videoItem.bvid, + ); if (cid != null) { PageUtils.toVideoPage( 'bvid=${videoItem.bvid}&cid=$cid', arguments: { 'videoItem': videoItem, - 'heroTag': Utils.makeHeroTag(videoItem.aid) + 'heroTag': Utils.makeHeroTag(videoItem.aid), }, ); } @@ -157,11 +163,12 @@ class VideoCardH extends StatelessWidget { ? 1 : progress / videoItem.duration, ), - ) + ), ] else if (videoItem.duration > 0) PBadge( text: DurationUtil.formatDuration( - videoItem.duration), + videoItem.duration, + ), right: 6.0, bottom: 6.0, type: PBadgeType.gray, @@ -214,22 +221,24 @@ class VideoCardH extends StatelessWidget { overflow: TextOverflow.ellipsis, maxLines: 2, TextSpan( - children: item.titleList! - .map((e) => TextSpan( - text: e.text, - style: TextStyle( - fontSize: - theme.textTheme.bodyMedium!.fontSize, - height: 1.42, - letterSpacing: 0.3, - color: e.isEm - ? theme.colorScheme.primary - : theme.colorScheme.onSurface, - ), - )) - .toList()), + children: item.titleList! + .map( + (e) => TextSpan( + text: e.text, + style: TextStyle( + fontSize: theme.textTheme.bodyMedium!.fontSize, + height: 1.42, + letterSpacing: 0.3, + color: e.isEm + ? theme.colorScheme.primary + : theme.colorScheme.onSurface, + ), + ), + ) + .toList(), + ), ), - ) + ), ] else Expanded( child: Text( diff --git a/lib/common/widgets/video_card/video_card_v.dart b/lib/common/widgets/video_card/video_card_v.dart index 2c1f0cd93..ff836214a 100644 --- a/lib/common/widgets/video_card/video_card_v.dart +++ b/lib/common/widgets/video_card/video_card_v.dart @@ -37,7 +37,8 @@ class VideoCardV extends StatelessWidget { break; case 'av': String bvid = videoItem.bvid ?? IdUtils.av2bv(videoItem.aid!); - int? cid = videoItem.cid ?? + int? cid = + videoItem.cid ?? await SearchHttp.ab2c(aid: videoItem.aid, bvid: bvid); if (cid != null) { PageUtils.toVideoPage( @@ -83,32 +84,35 @@ class VideoCardV extends StatelessWidget { children: [ AspectRatio( aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder(builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - src: videoItem.cover, - width: maxWidth, - height: maxHeight, - radius: 0, - ), - if (videoItem.duration > 0) - PBadge( - bottom: 6, - right: 7, - size: PBadgeSize.small, - type: PBadgeType.gray, - text: - DurationUtil.formatDuration(videoItem.duration), - ) - ], - ); - }), + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + src: videoItem.cover, + width: maxWidth, + height: maxHeight, + radius: 0, + ), + if (videoItem.duration > 0) + PBadge( + bottom: 6, + right: 7, + size: PBadgeSize.small, + type: PBadgeType.gray, + text: DurationUtil.formatDuration( + videoItem.duration, + ), + ), + ], + ); + }, + ), ), - content(context) + content(context), ], ), ), @@ -193,7 +197,7 @@ class VideoCardV extends StatelessWidget { ), ), ), - if (videoItem.goto == 'av') const SizedBox(width: 10) + if (videoItem.goto == 'av') const SizedBox(width: 10), ], ), ], @@ -236,7 +240,7 @@ class VideoCardV extends StatelessWidget { ), ), const SizedBox(width: 2), - ] + ], // deprecated // else if (videoItem is RecVideoItemAppModel && // videoItem.desc != null && diff --git a/lib/common/widgets/video_popup_menu.dart b/lib/common/widgets/video_popup_menu.dart index 625770dcc..b00def7fd 100644 --- a/lib/common/widgets/video_popup_menu.dart +++ b/lib/common/widgets/video_popup_menu.dart @@ -146,7 +146,8 @@ class VideoCustomActions { ); SmartDialog.dismiss(); SmartDialog.showToast( - res['status'] ? "成功" : res['msg']); + res['status'] ? "成功" : res['msg'], + ); Get.back(); }, style: FilledButton.styleFrom( @@ -181,7 +182,9 @@ class VideoCustomActions { Get.back(); SmartDialog.showLoading(msg: '正在提交'); var res = await VideoHttp.dislikeVideo( - bvid: videoItem.bvid!, type: true); + bvid: videoItem.bvid!, + type: true, + ); SmartDialog.dismiss(); SmartDialog.showToast( res['status'] ? "点踩成功" : res['msg'], @@ -200,10 +203,13 @@ class VideoCustomActions { Get.back(); SmartDialog.showLoading(msg: '正在提交'); var res = await VideoHttp.dislikeVideo( - bvid: videoItem.bvid!, type: false); + bvid: videoItem.bvid!, + type: false, + ); SmartDialog.dismiss(); SmartDialog.showToast( - res['status'] ? "取消踩" : res['msg']); + res['status'] ? "取消踩" : res['msg'], + ); }, style: FilledButton.styleFrom( visualDensity: VisualDensity.compact, @@ -211,7 +217,7 @@ class VideoCustomActions { child: const Text("撤销"), ), ], - ) + ), ], ), ), @@ -231,16 +237,18 @@ class VideoCustomActions { builder: (context) { return AlertDialog( title: const Text('提示'), - content: - Text('确定拉黑:${videoItem.owner.name}(${videoItem.owner.mid})?' - '\n\n注:被拉黑的Up可以在隐私设置-黑名单管理中解除'), + content: Text( + '确定拉黑:${videoItem.owner.name}(${videoItem.owner.mid})?' + '\n\n注:被拉黑的Up可以在隐私设置-黑名单管理中解除', + ), actions: [ TextButton( onPressed: Get.back, child: Text( '点错了', style: TextStyle( - color: Theme.of(context).colorScheme.outline), + color: Theme.of(context).colorScheme.outline, + ), ), ), TextButton( @@ -258,7 +266,7 @@ class VideoCustomActions { SmartDialog.showToast(res['msg'] ?? '成功'); }, child: const Text('确认'), - ) + ), ], ); }, @@ -271,7 +279,7 @@ class VideoCustomActions { ? const Icon(MdiIcons.incognitoOff, size: 16) : const Icon(MdiIcons.incognito, size: 16), MineController.onChangeAnonymity, - ) + ), ]; } } @@ -295,34 +303,35 @@ class VideoPopupMenu extends StatelessWidget { @override Widget build(BuildContext context) { return ExcludeSemantics( - child: SizedBox( - width: size, - height: size, - child: PopupMenuButton( - padding: EdgeInsets.zero, - icon: Icon( - Icons.more_vert_outlined, - color: Theme.of(context).colorScheme.outline, - size: iconSize, + child: SizedBox( + width: size, + height: size, + child: PopupMenuButton( + padding: EdgeInsets.zero, + icon: Icon( + Icons.more_vert_outlined, + color: Theme.of(context).colorScheme.outline, + size: iconSize, + ), + position: PopupMenuPosition.under, + onSelected: (String type) {}, + itemBuilder: (BuildContext context) => + VideoCustomActions(videoItem, context, onRemove).actions.map((e) { + return PopupMenuItem( + value: e.value, + height: menuItemHeight, + onTap: e.onTap, + child: Row( + children: [ + e.icon, + const SizedBox(width: 6), + Text(e.title, style: const TextStyle(fontSize: 13)), + ], + ), + ); + }).toList(), ), - position: PopupMenuPosition.under, - onSelected: (String type) {}, - itemBuilder: (BuildContext context) => - VideoCustomActions(videoItem, context, onRemove).actions.map((e) { - return PopupMenuItem( - value: e.value, - height: menuItemHeight, - onTap: e.onTap, - child: Row( - children: [ - e.icon, - const SizedBox(width: 6), - Text(e.title, style: const TextStyle(fontSize: 13)) - ], - ), - ); - }).toList(), ), - )); + ); } } diff --git a/lib/grpc/grpc_req.dart b/lib/grpc/grpc_req.dart index 67cd7e28d..6c5691ef6 100644 --- a/lib/grpc/grpc_req.dart +++ b/lib/grpc/grpc_req.dart @@ -39,15 +39,17 @@ class GrpcReq { } else { headers.remove('authorization'); } - headers['x-bili-metadata-bin'] = base64Encode(Metadata( - accessKey: _accessKey ?? '', - mobiApp: _mobiApp, - device: _device, - build: _build, - channel: _biliChannel, - buvid: _buvid, - platform: _device, - ).writeToBuffer()); + headers['x-bili-metadata-bin'] = base64Encode( + Metadata( + accessKey: _accessKey ?? '', + mobiApp: _mobiApp, + device: _device, + build: _build, + channel: _biliChannel, + buvid: _buvid, + platform: _device, + ).writeToBuffer(), + ); options = Options(headers: headers, responseType: ResponseType.bytes); } @@ -63,45 +65,57 @@ class GrpcReq { 'buvid': _buvid, 'bili-http-engine': 'cronet', 'te': 'trailers', - 'x-bili-fawkes-req-bin': base64Encode(FawkesReq( - appkey: _mobiApp, - env: 'prod', - sessionId: _sessionId, - ).writeToBuffer()), - 'x-bili-metadata-bin': base64Encode(Metadata( - accessKey: _accessKey ?? '', - mobiApp: _mobiApp, - device: _device, - build: _build, - channel: _biliChannel, - buvid: _buvid, - platform: _device, - ).writeToBuffer()), - 'x-bili-device-bin': base64Encode(Device( - appId: 5, - build: _build, - buvid: _buvid, - mobiApp: _mobiApp, - platform: _device, - channel: _biliChannel, - brand: _device, - model: _device, - osver: '15', - versionName: _versionName, - ).writeToBuffer()), - 'x-bili-network-bin': base64Encode(network.Network( - type: network.NetworkType.WIFI, - ).writeToBuffer()), - 'x-bili-locale-bin': base64Encode(Locale( - cLocale: LocaleIds(language: 'zh', region: 'CN', script: 'Hans'), - sLocale: LocaleIds(language: 'zh', region: 'CN', script: 'Hans'), - timezone: 'Asia/Shanghai', - ).writeToBuffer()), + 'x-bili-fawkes-req-bin': base64Encode( + FawkesReq( + appkey: _mobiApp, + env: 'prod', + sessionId: _sessionId, + ).writeToBuffer(), + ), + 'x-bili-metadata-bin': base64Encode( + Metadata( + accessKey: _accessKey ?? '', + mobiApp: _mobiApp, + device: _device, + build: _build, + channel: _biliChannel, + buvid: _buvid, + platform: _device, + ).writeToBuffer(), + ), + 'x-bili-device-bin': base64Encode( + Device( + appId: 5, + build: _build, + buvid: _buvid, + mobiApp: _mobiApp, + platform: _device, + channel: _biliChannel, + brand: _device, + model: _device, + osver: '15', + versionName: _versionName, + ).writeToBuffer(), + ), + 'x-bili-network-bin': base64Encode( + network.Network( + type: network.NetworkType.WIFI, + ).writeToBuffer(), + ), + 'x-bili-locale-bin': base64Encode( + Locale( + cLocale: LocaleIds(language: 'zh', region: 'CN', script: 'Hans'), + sLocale: LocaleIds(language: 'zh', region: 'CN', script: 'Hans'), + timezone: 'Asia/Shanghai', + ).writeToBuffer(), + ), 'x-bili-exps-bin': '', }; - static Options options = - Options(headers: headers, responseType: ResponseType.bytes); + static Options options = Options( + headers: headers, + responseType: ResponseType.bytes, + ); static Uint8List compressProtobuf(Uint8List proto) { proto = const GZipEncoder().encodeBytes(proto); @@ -122,10 +136,16 @@ class GrpcReq { } } - static Future> request(String url, - GeneratedMessage request, T Function(Uint8List) grpcParser) async { - final response = await Request().post(HttpString.appBaseUrl + url, - data: compressProtobuf(request.writeToBuffer()), options: options); + static Future> request( + String url, + GeneratedMessage request, + T Function(Uint8List) grpcParser, + ) async { + final response = await Request().post( + HttpString.appBaseUrl + url, + data: compressProtobuf(request.writeToBuffer()), + options: options, + ); if (response.data is Map) { return Error(response.data['message']); @@ -151,8 +171,9 @@ class GrpcReq { try { final grpcMsg = Status.fromBuffer(msgBytes); // UNKNOWN : -400 : msg - final errMsg = - grpcMsg.details.map((e) => e.status.message).join('\n'); + final errMsg = grpcMsg.details + .map((e) => e.status.message) + .join('\n'); msg = kDebugMode ? 'CODE: ${grpcMsg.code}(${grpcMsg.message})\nMSG: $errMsg' : errMsg; diff --git a/lib/grpc/im.dart b/lib/grpc/im.dart index 335f6424f..a58b591fc 100644 --- a/lib/grpc/im.dart +++ b/lib/grpc/im.dart @@ -153,8 +153,9 @@ class ImGrpc { ); } - static Future> getImSettings( - {IMSettingType? type}) { + static Future> getImSettings({ + IMSettingType? type, + }) { return GrpcReq.request( GrpcUrl.getImSettings, GetImSettingsReq( @@ -164,8 +165,9 @@ class ImGrpc { ); } - static Future> setImSettings( - {PbMap? settings}) { + static Future> setImSettings({ + PbMap? settings, + }) { return GrpcReq.request( GrpcUrl.setImSettings, SetImSettingsReq( @@ -184,7 +186,8 @@ class ImGrpc { } static Future> keywordBlockingAdd( - String keyword) { + String keyword, + ) { return GrpcReq.request( GrpcUrl.keywordBlockingAdd, KeywordBlockingAddReq(keyword: keyword), @@ -193,7 +196,8 @@ class ImGrpc { } static Future> keywordBlockingDelete( - String keyword) { + String keyword, + ) { return GrpcReq.request( GrpcUrl.keywordBlockingDelete, KeywordBlockingDeleteReq(keyword: keyword), @@ -201,8 +205,9 @@ class ImGrpc { ); } - static Future> getTotalUnread( - {int? unreadType}) { + static Future> getTotalUnread({ + int? unreadType, + }) { return GrpcReq.request( GrpcUrl.getTotalUnread, ReqTotalUnread(unreadType: unreadType, showUnfollowList: 1), diff --git a/lib/grpc/reply.dart b/lib/grpc/reply.dart index 90d95115a..48c2e96d4 100644 --- a/lib/grpc/reply.dart +++ b/lib/grpc/reply.dart @@ -9,8 +9,10 @@ import 'package:fixnum/fixnum.dart'; class ReplyGrpc { static bool antiGoodsReply = Pref.antiGoodsReply; - static RegExp replyRegExp = - RegExp(Pref.banWordForReply, caseSensitive: false); + static RegExp replyRegExp = RegExp( + Pref.banWordForReply, + caseSensitive: false, + ); static bool enableFilter = replyRegExp.pattern.isNotEmpty; // static Future replyInfo({required int rpid}) { diff --git a/lib/http/black.dart b/lib/http/black.dart index 4f4e4f4d5..9c5f14e9b 100644 --- a/lib/http/black.dart +++ b/lib/http/black.dart @@ -5,8 +5,10 @@ import 'package:PiliPlus/models_new/blacklist/data.dart'; import 'package:PiliPlus/utils/accounts.dart'; class BlackHttp { - static Future> blackList( - {required int pn, int? ps}) async { + static Future> blackList({ + required int pn, + int? ps, + }) async { var res = await Request().get( Api.blackLst, queryParameters: { diff --git a/lib/http/common.dart b/lib/http/common.dart index e314cc362..952d048cd 100644 --- a/lib/http/common.dart +++ b/lib/http/common.dart @@ -3,15 +3,18 @@ import 'package:PiliPlus/http/init.dart'; class CommonHttp { static Future unReadDynamic() async { - var res = await Request().get(Api.getUnreadDynamic, queryParameters: { - 'alltype_offset': 0, - 'video_offset': 0, - 'article_offset': 0, - }); + var res = await Request().get( + Api.getUnreadDynamic, + queryParameters: { + 'alltype_offset': 0, + 'video_offset': 0, + 'article_offset': 0, + }, + ); if (res.data['code'] == 0) { return { 'status': true, - 'data': res.data['data']['update_info']['item']['count'] + 'data': res.data['data']['update_info']['item']['count'], }; } else { return { diff --git a/lib/http/danmaku_block.dart b/lib/http/danmaku_block.dart index fbce701a1..59fb71ce5 100644 --- a/lib/http/danmaku_block.dart +++ b/lib/http/danmaku_block.dart @@ -9,7 +9,7 @@ class DanmakuFilterHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': DanmakuBlockDataModel.fromJson(res.data['data']) + 'data': DanmakuBlockDataModel.fromJson(res.data['data']), }; } else { return { @@ -37,8 +37,10 @@ class DanmakuFilterHttp { } } - static Future danmakuFilterAdd( - {required String filter, required int type}) async { + static Future danmakuFilterAdd({ + required String filter, + required int type, + }) async { var res = await Request().post( Api.danmakuFilterAdd, queryParameters: { diff --git a/lib/http/dynamics.dart b/lib/http/dynamics.dart index c25b9d7ab..856d3b47e 100644 --- a/lib/http/dynamics.dart +++ b/lib/http/dynamics.dart @@ -168,16 +168,16 @@ class DynamicsHttp { "scene": rid != null ? 5 : dynIdStr != null - ? 4 - : pics != null - ? 2 - : 1, + ? 4 + : pics != null + ? 2 + : 1, 'pics': ?pics, "attach_card": attachCard, "upload_id": "${rid != null ? 0 : mid}_${DateTime.now().millisecondsSinceEpoch ~/ 1000}_${Utils.random.nextInt(9000) + 1000}", "meta": { - "app_meta": {"from": "create.dynamic.web", "mobi_app": "web"} + "app_meta": {"from": "create.dynamic.web", "mobi_app": "web"}, }, if (topic != null) "topic": { @@ -185,7 +185,7 @@ class DynamicsHttp { "name": topic.second, "from_source": "dyn.web.list", "from_topic_id": 0, - } + }, }, if (dynIdStr != null || rid != null) "web_repost_src": { @@ -194,8 +194,8 @@ class DynamicsHttp { "revs_id": { "dyn_type": dynType, "rid": rid, - } - } + }, + }, }, ); if (res.data['code'] == 0) { @@ -309,15 +309,16 @@ class DynamicsHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': ArticleInfoData.fromJson(res.data['data']) + 'data': ArticleInfoData.fromJson(res.data['data']), }; } else { return {'status': false, 'msg': res.data['message']}; } } - static Future> articleView( - {required dynamic cvId}) async { + static Future> articleView({ + required dynamic cvId, + }) async { final res = await Request().get( Api.articleView, queryParameters: await WbiSign.makSign({ @@ -333,8 +334,9 @@ class DynamicsHttp { } } - static Future> opusDetail( - {required dynamic opusId}) async { + static Future> opusDetail({ + required dynamic opusId, + }) async { final res = await Request().get( Api.opusDetail, queryParameters: await WbiSign.makSign({ @@ -351,8 +353,10 @@ class DynamicsHttp { } static Future> voteInfo(dynamic voteId) async { - final res = - await Request().get(Api.voteInfo, queryParameters: {'vote_id': voteId}); + final res = await Request().get( + Api.voteInfo, + queryParameters: {'vote_id': voteId}, + ); if (res.data['code'] == 0) { return Success(VoteInfo.fromSeparatedJson(res.data['data'])); } else { @@ -375,12 +379,14 @@ class DynamicsHttp { 'op_bit': 0, 'dynamic_id': dynamicId ?? 0, 'csrf_token': csrf, - 'csrf': csrf + 'csrf': csrf, }; - final res = await Request().post(Api.doVote, - queryParameters: {'csrf': csrf}, - data: data, - options: Options(contentType: Headers.jsonContentType)); + final res = await Request().post( + Api.doVote, + queryParameters: {'csrf': csrf}, + data: data, + options: Options(contentType: Headers.jsonContentType), + ); if (res.data['code'] == 0) { return Success(VoteInfo.fromJson(res.data['data']['vote_info'])); } else { @@ -471,15 +477,16 @@ class DynamicsHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': DynReserveData.fromJson(res.data['data']) + 'data': DynReserveData.fromJson(res.data['data']), }; } else { return {'status': false, 'msg': res.data['message']}; } } - static Future?>> dynTopicRcmd( - {int ps = 25}) async { + static Future?>> dynTopicRcmd({ + int ps = 25, + }) async { final res = await Request().get( Api.dynTopicRcmd, queryParameters: { @@ -489,9 +496,11 @@ class DynamicsHttp { }, ); if (res.data['code'] == 0) { - return Success((res.data['data']?['topic_items'] as List?) - ?.map((e) => TopicItem.fromJson(e)) - .toList()); + return Success( + (res.data['data']?['topic_items'] as List?) + ?.map((e) => TopicItem.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } @@ -506,16 +515,19 @@ class DynamicsHttp { }, ); if (res.data['code'] == 0) { - return Success((res.data['data'] as List?) - ?.map((e) => OpusPicModel.fromJson(e)) - .toList()); + return Success( + (res.data['data'] as List?) + ?.map((e) => OpusPicModel.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } } - static Future?>> dynMention( - {String? keyword}) async { + static Future?>> dynMention({ + String? keyword, + }) async { final res = await Request().get( Api.dynMention, queryParameters: { diff --git a/lib/http/fan.dart b/lib/http/fan.dart index 9f35ede4f..91c2ee4bc 100644 --- a/lib/http/fan.dart +++ b/lib/http/fan.dart @@ -4,15 +4,22 @@ import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/fans/data.dart'; class FanHttp { - static Future> fans( - {int? vmid, int? pn, int? ps, String? orderType}) async { - var res = await Request().get(Api.fans, queryParameters: { - 'vmid': vmid, - 'pn': pn, - 'ps': ps, - 'order': 'desc', - 'order_type': orderType, - }); + static Future> fans({ + int? vmid, + int? pn, + int? ps, + String? orderType, + }) async { + var res = await Request().get( + Api.fans, + queryParameters: { + 'vmid': vmid, + 'pn': pn, + 'ps': ps, + 'order': 'desc', + 'order_type': orderType, + }, + ); if (res.data['code'] == 0) { return Success(FansData.fromJson(res.data['data'])); } else { diff --git a/lib/http/fav.dart b/lib/http/fav.dart index 21f6a6ca5..bbddb5e0d 100644 --- a/lib/http/fav.dart +++ b/lib/http/fav.dart @@ -67,7 +67,7 @@ class FavHttp { 'order': order.name, 'type': type, 'tid': 0, - 'platform': 'web' + 'platform': 'web', }, ); if (res.data['code'] == 0) { @@ -444,15 +444,17 @@ class FavHttp { static Future deleteFolder({ required List mediaIds, }) async { - var res = await Request().post(Api.deleteFolder, - data: { - 'media_ids': mediaIds.join(','), - 'platform': 'web', - 'csrf': Accounts.main.csrf, - }, - options: Options( - contentType: Headers.formUrlEncodedContentType, - )); + var res = await Request().post( + Api.deleteFolder, + data: { + 'media_ids': mediaIds.join(','), + 'platform': 'web', + 'csrf': Accounts.main.csrf, + }, + options: Options( + contentType: Headers.formUrlEncodedContentType, + ), + ); if (res.data['code'] == 0) { return {'status': true, 'data': res.data['data']}; } else { @@ -468,18 +470,20 @@ class FavHttp { required String cover, required String intro, }) async { - var res = await Request().post(isAdd ? Api.addFolder : Api.editFolder, - data: { - 'title': title, - 'intro': intro, - 'privacy': privacy, - 'cover': cover.isNotEmpty ? Uri.encodeFull(cover) : cover, - 'csrf': Accounts.main.csrf, - 'media_id': ?mediaId, - }, - options: Options( - contentType: Headers.formUrlEncodedContentType, - )); + var res = await Request().post( + isAdd ? Api.addFolder : Api.editFolder, + data: { + 'title': title, + 'intro': intro, + 'privacy': privacy, + 'cover': cover.isNotEmpty ? Uri.encodeFull(cover) : cover, + 'csrf': Accounts.main.csrf, + 'media_id': ?mediaId, + }, + options: Options( + contentType: Headers.formUrlEncodedContentType, + ), + ); if (res.data['code'] == 0) { return {'status': true, 'data': FavFolderInfo.fromJson(res.data['data'])}; } else { @@ -554,9 +558,11 @@ class FavHttp { ), ); if (res.data['code'] == 0) { - return Success((res.data['data'] as List?) - ?.map((e) => SpaceFavData.fromJson(e)) - .toList()); + return Success( + (res.data['data'] as List?) + ?.map((e) => SpaceFavData.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } @@ -574,7 +580,7 @@ class FavHttp { data: { "entity": { "object_id_str": opusId, - "type": {"biz": 2} + "type": {"biz": 2}, }, "action": action, // 3 fav, 4 unfav }, @@ -644,11 +650,11 @@ class FavHttp { var res = await Request().post( isFav ? isCopy - ? Api.copyFav - : Api.moveFav + ? Api.copyFav + : Api.moveFav : isCopy - ? Api.copyToview - : Api.moveToview, + ? Api.copyToview + : Api.moveToview, data: { 'src_media_id': ?srcMediaId, 'tar_media_id': tarMediaId, diff --git a/lib/http/follow.dart b/lib/http/follow.dart index 00fd6ad1b..0b3e7f364 100644 --- a/lib/http/follow.dart +++ b/lib/http/follow.dart @@ -10,13 +10,16 @@ class FollowHttp { int? ps, String orderType = '', }) async { - var res = await Request().get(Api.followings, queryParameters: { - 'vmid': vmid, - 'pn': pn, - 'ps': ps, - 'order': 'desc', - 'order_type': orderType, - }); + var res = await Request().get( + Api.followings, + queryParameters: { + 'vmid': vmid, + 'pn': pn, + 'ps': ps, + 'order': 'desc', + 'order_type': orderType, + }, + ); if (res.data['code'] == 0) { return Success( FollowData.fromJson(res.data['data']), @@ -32,13 +35,16 @@ class FollowHttp { int? ps, String orderType = '', // ''=>最近关注,'attention'=>最常访问 }) async { - var res = await Request().get(Api.followings, queryParameters: { - 'vmid': vmid, - 'pn': pn, - 'ps': ps, - 'order': 'desc', - 'order_type': orderType, - }); + var res = await Request().get( + Api.followings, + queryParameters: { + 'vmid': vmid, + 'pn': pn, + 'ps': ps, + 'order': 'desc', + 'order_type': orderType, + }, + ); if (res.data['code'] == 0) { return Success( diff --git a/lib/http/init.dart b/lib/http/init.dart index 64646750b..527aa6af4 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -37,7 +37,9 @@ class Request { Accounts.refresh(); final List cookies = Accounts.main.cookieJar.toList(); final webManager = web.CookieManager(); - await Future.wait(cookies.map((item) => webManager.setCookie( + await Future.wait( + cookies.map( + (item) => webManager.setCookie( url: web.WebUri(item.domain ?? ''), name: item.name, value: item.value, @@ -45,7 +47,9 @@ class Request { domain: item.domain, isSecure: item.secure, isHttpOnly: item.httpOnly, - ))); + ), + ), + ); if (Accounts.main.isLogin) { final coin = GStorage.userInfo.get('userInfoCache')?.money; @@ -73,10 +77,11 @@ class Request { // options: Options(extra: {'account': account})); // final String spmPrefix = _spmPrefixExp.firstMatch(html.data)!.group(1)!; final String randPngEnd = base64.encode( - List.generate(32, (_) => Utils.random.nextInt(256)) + - List.filled(4, 0) + - [73, 69, 78, 68] + - List.generate(4, (_) => Utils.random.nextInt(256))); + List.generate(32, (_) => Utils.random.nextInt(256)) + + List.filled(4, 0) + + [73, 69, 78, 68] + + List.generate(4, (_) => Utils.random.nextInt(256)), + ); String jsonData = json.encode({ '3064': 1, @@ -88,9 +93,11 @@ class Request { }, }); - await Request().post(Api.activateBuvidApi, - data: {'payload': jsonData}, - options: Options(contentType: Headers.jsonContentType)); + await Request().post( + Api.activateBuvidApi, + data: {'payload': jsonData}, + options: Options(contentType: Headers.jsonContentType), + ); } catch (_) {} } @@ -100,68 +107,74 @@ class Request { Request._internal() { //BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数 BaseOptions options = BaseOptions( - //请求基地址,可以包含子路径 - baseUrl: HttpString.apiBaseUrl, - //连接服务器超时时间,单位是毫秒. - connectTimeout: const Duration(milliseconds: 10000), - //响应流上前后两次接受到数据的间隔,单位为毫秒。 - receiveTimeout: const Duration(milliseconds: 10000), - //Http请求头. - headers: { - 'connection': 'keep-alive', - 'accept-encoding': 'br,gzip', - 'user-agent': 'Dart/3.6 (dart:io)', // Http2Adapter不会自动添加标头 - 'referer': HttpString.baseUrl, - 'env': 'prod', - 'app-key': 'android64', - 'x-bili-aurora-zone': 'sh001', - }, - responseDecoder: responseDecoder, // Http2Adapter没有自动解压 - persistentConnection: true); + //请求基地址,可以包含子路径 + baseUrl: HttpString.apiBaseUrl, + //连接服务器超时时间,单位是毫秒. + connectTimeout: const Duration(milliseconds: 10000), + //响应流上前后两次接受到数据的间隔,单位为毫秒。 + receiveTimeout: const Duration(milliseconds: 10000), + //Http请求头. + headers: { + 'connection': 'keep-alive', + 'accept-encoding': 'br,gzip', + 'user-agent': 'Dart/3.6 (dart:io)', // Http2Adapter不会自动添加标头 + 'referer': HttpString.baseUrl, + 'env': 'prod', + 'app-key': 'android64', + 'x-bili-aurora-zone': 'sh001', + }, + responseDecoder: responseDecoder, // Http2Adapter没有自动解压 + persistentConnection: true, + ); final bool enableSystemProxy = Pref.enableSystemProxy; final String systemProxyHost = Pref.systemProxyHost; final String systemProxyPort = Pref.systemProxyPort; - final http11Adapter = IOHttpClientAdapter(createHttpClient: () { - final client = HttpClient() - ..idleTimeout = const Duration(seconds: 15) - ..autoUncompress = false; // Http2Adapter没有自动解压, 统一行为 - // 设置代理 - if (enableSystemProxy) { - client - ..findProxy = ((_) => 'PROXY $systemProxyHost:$systemProxyPort') - ..badCertificateCallback = - (X509Certificate cert, String host, int port) => true; - } - return client; - }); + final http11Adapter = IOHttpClientAdapter( + createHttpClient: () { + final client = HttpClient() + ..idleTimeout = const Duration(seconds: 15) + ..autoUncompress = false; // Http2Adapter没有自动解压, 统一行为 + // 设置代理 + if (enableSystemProxy) { + client + ..findProxy = ((_) => 'PROXY $systemProxyHost:$systemProxyPort') + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } + return client; + }, + ); late Uri proxy; if (enableSystemProxy) { proxy = Uri( - scheme: 'http', - host: systemProxyHost, - port: int.parse(systemProxyPort)); + scheme: 'http', + host: systemProxyHost, + port: int.parse(systemProxyPort), + ); } dio = Dio(options) ..httpClientAdapter = Pref.enableHttp2 ? Http2Adapter( ConnectionManager( - idleTimeout: const Duration(seconds: 15), - onClientCreate: enableSystemProxy - ? (_, config) { - config - ..proxy = proxy - ..onBadCertificate = (_) => true; - } - : Pref.badCertificateCallback - ? (_, config) { - config.onBadCertificate = (_) => true; - } - : null), - fallbackAdapter: http11Adapter) + idleTimeout: const Duration(seconds: 15), + onClientCreate: enableSystemProxy + ? (_, config) { + config + ..proxy = proxy + ..onBadCertificate = (_) => true; + } + : Pref.badCertificateCallback + ? (_, config) { + config.onBadCertificate = (_) => true; + } + : null, + ), + fallbackAdapter: http11Adapter, + ) : http11Adapter; // 先于其他Interceptor @@ -169,11 +182,13 @@ class Request { // 日志拦截器 输出请求、响应内容 if (kDebugMode) { - dio.interceptors.add(LogInterceptor( - request: false, - requestHeader: false, - responseHeader: false, - )); + dio.interceptors.add( + LogInterceptor( + request: false, + requestHeader: false, + responseHeader: false, + ), + ); } dio.transformer = BackgroundTransformer(); @@ -208,7 +223,7 @@ class Request { } on DioException catch (e) { return Response( data: { - 'message': await AccountManager.dioError(e) + 'message': await AccountManager.dioError(e), }, // 将自定义 Map 数据赋值给 Response 的 data 属性 statusCode: e.response?.statusCode ?? -1, requestOptions: e.requestOptions, @@ -239,7 +254,7 @@ class Request { AccountManager.toast(e); return Response( data: { - 'message': await AccountManager.dioError(e) + 'message': await AccountManager.dioError(e), }, // 将自定义 Map 数据赋值给 Response 的 data 属性 statusCode: e.response?.statusCode ?? -1, requestOptions: e.requestOptions, @@ -250,8 +265,11 @@ class Request { /* * 下载文件 */ - Future downloadFile(String urlPath, String savePath, - {CancelToken? cancelToken}) async { + Future downloadFile( + String urlPath, + String savePath, { + CancelToken? cancelToken, + }) async { try { final response = await dio.download( urlPath, @@ -291,19 +309,26 @@ class Request { 'mob' => 'Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36', _ => - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15' + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15', }; } - static String responseDecoder(List responseBytes, RequestOptions options, - ResponseBody responseBody) { + static String responseDecoder( + List responseBytes, + RequestOptions options, + ResponseBody responseBody, + ) { switch (responseBody.headers['content-encoding']?.firstOrNull) { case 'gzip': - return utf8.decode(_gzipDecoder.decodeBytes(responseBytes), - allowMalformed: true); + return utf8.decode( + _gzipDecoder.decodeBytes(responseBytes), + allowMalformed: true, + ); case 'br': - return utf8.decode(_brotilDecoder.convert(responseBytes), - allowMalformed: true); + return utf8.decode( + _brotilDecoder.convert(responseBytes), + allowMalformed: true, + ); default: return utf8.decode(responseBytes, allowMalformed: true); } diff --git a/lib/http/live.dart b/lib/http/live.dart index f66ec90bd..86602dd50 100644 --- a/lib/http/live.dart +++ b/lib/http/live.dart @@ -83,7 +83,7 @@ class LiveHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': RoomPlayInfoData.fromJson(res.data['data']) + 'data': RoomPlayInfoData.fromJson(res.data['data']), }; } else { return {'status': false, 'msg': res.data['message']}; @@ -91,13 +91,16 @@ class LiveHttp { } static Future liveRoomInfoH5({roomId, qn}) async { - var res = await Request().get(Api.liveRoomInfoH5, queryParameters: { - 'room_id': roomId, - }); + var res = await Request().get( + Api.liveRoomInfoH5, + queryParameters: { + 'room_id': roomId, + }, + ); if (res.data['code'] == 0) { return { 'status': true, - 'data': RoomInfoH5Data.fromJson(res.data['data']) + 'data': RoomInfoH5Data.fromJson(res.data['data']), }; } else { return {'status': false, 'msg': res.data['message']}; @@ -133,15 +136,16 @@ class LiveHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': LiveDmInfoData.fromJson(res.data['data']) + 'data': LiveDmInfoData.fromJson(res.data['data']), }; } else { return {'status': false, 'msg': res.data['message']}; } } - static Future?>> getLiveEmoticons( - {required int roomId}) async { + static Future?>> getLiveEmoticons({ + required int roomId, + }) async { var res = await Request().get( Api.getLiveEmoticons, queryParameters: { @@ -295,9 +299,11 @@ class LiveHttp { queryParameters: params, ); if (res.data['code'] == 0) { - return Success((res.data['data']?['list'] as List?) - ?.map((e) => AreaList.fromJson(e)) - .toList()); + return Success( + (res.data['data']?['list'] as List?) + ?.map((e) => AreaList.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } @@ -331,10 +337,12 @@ class LiveHttp { ); if (res.data['code'] == 0) { - return Success((res.data['data']?['tags'] as List?) - ?.map((e) => AreaItem.fromJson(e)) - .toList() ?? - []); + return Success( + (res.data['data']?['tags'] as List?) + ?.map((e) => AreaItem.fromJson(e)) + .toList() ?? + [], + ); } else { return Error(res.data['message']); } @@ -409,9 +417,9 @@ class LiveHttp { queryParameters: params, ); if (res.data['code'] == 0) { - return Success((res.data['data'] as List?) - ?.map((e) => AreaItem.fromJson(e)) - .toList()); + return Success( + (res.data['data'] as List?)?.map((e) => AreaItem.fromJson(e)).toList(), + ); } else { return Error(res.data['message']); } @@ -458,7 +466,8 @@ class LiveHttp { } static Future> getLiveInfoByUser( - dynamic roomId) async { + dynamic roomId, + ) async { var res = await Request().get( Api.getLiveInfoByUser, queryParameters: await WbiSign.makSign({ diff --git a/lib/http/loading_state.dart b/lib/http/loading_state.dart index 55abf3c27..e1f4f447f 100644 --- a/lib/http/loading_state.dart +++ b/lib/http/loading_state.dart @@ -8,14 +8,14 @@ sealed class LoadingState { bool get isSuccess => this is Success; T get data => switch (this) { - Success(:var response) => response, - _ => throw this, - }; + Success(:var response) => response, + _ => throw this, + }; T? get dataOrNull => switch (this) { - Success(:var response) => response, - _ => null, - }; + Success(:var response) => response, + _ => null, + }; void toast() => SmartDialog.showToast(toString()); } diff --git a/lib/http/login.dart b/lib/http/login.dart index 7bea5fc03..0dcabd666 100644 --- a/lib/http/login.dart +++ b/lib/http/login.dart @@ -57,7 +57,7 @@ class LoginHttp { 'status': res.data['code'] == 0, 'code': res.data['code'], 'data': res.data['data'], - 'msg': res.data['message'] + 'msg': res.data['message'], }; } @@ -107,8 +107,9 @@ class LoginHttp { 'gee_validate': ?geeValidate, 'local_id': buvid, // https://chinggg.github.io/post/appre/ - 'login_session_id': - md5.convert(utf8.encode(buvid + timestamp.toString())).toString(), + 'login_session_id': md5 + .convert(utf8.encode(buvid + timestamp.toString())) + .toString(), 'mobi_app': 'android_hd', 'platform': 'android', 'recaptcha_token': ?recaptchaToken, @@ -135,7 +136,7 @@ class LoginHttp { 'status': false, 'code': res.data['code'], 'msg': res.data['message'], - 'data': res.data['data'] + 'data': res.data['data'], }; } } @@ -191,8 +192,9 @@ class LoginHttp { String? recaptchaToken, }) async { dynamic publicKey = RSAKeyParser().parse(key); - String passwordEncrypted = - Encrypter(RSA(publicKey: publicKey)).encrypt(salt + password).base64; + String passwordEncrypted = Encrypter( + RSA(publicKey: publicKey), + ).encrypt(salt + password).base64; Map data = { 'bili_local_id': deviceId, @@ -206,9 +208,11 @@ class LoginHttp { 'device_name': 'vivo', 'device_platform': 'Android14vivo', 'disable_rcmd': '0', - 'dt': Uri.encodeComponent(Encrypter(RSA(publicKey: publicKey)) - .encrypt(Utils.generateRandomString(16)) - .base64), + 'dt': Uri.encodeComponent( + Encrypter( + RSA(publicKey: publicKey), + ).encrypt(Utils.generateRandomString(16)).base64, + ), 'from_pv': 'main.homepage.avatar-nologin.all.click', 'from_url': Uri.encodeComponent('bilibili://pegasus/promo'), 'gee_challenge': ?geeChallenge, @@ -247,7 +251,7 @@ class LoginHttp { 'status': false, 'code': res.data['code'], 'msg': res.data['message'], - 'data': res.data['data'] + 'data': res.data['data'], }; } } @@ -277,9 +281,11 @@ class LoginHttp { 'device_platform': 'Android14vivo', // 'device_tourist_id': '', 'disable_rcmd': '0', - 'dt': Uri.encodeComponent(Encrypter(RSA(publicKey: publicKey)) - .encrypt(Utils.generateRandomString(16)) - .base64), + 'dt': Uri.encodeComponent( + Encrypter( + RSA(publicKey: publicKey), + ).encrypt(Utils.generateRandomString(16)).base64, + ), 'from_pv': 'main.my-information.my-login.0.click', 'from_url': Uri.encodeComponent('bilibili://user_center/mine'), 'local_id': buvid, @@ -308,7 +314,7 @@ class LoginHttp { 'status': false, 'code': res.data['code'], 'msg': res.data['message'], - 'data': res.data['data'] + 'data': res.data['data'], }; } } @@ -330,7 +336,7 @@ class LoginHttp { 'status': false, 'code': res.data['code'], 'msg': res.data['message'], - 'data': res.data['data'] + 'data': res.data['data'], }; } } @@ -346,7 +352,7 @@ class LoginHttp { 'status': false, 'code': res.data['code'], 'msg': res.data['message'], - 'data': res.data['data'] + 'data': res.data['data'], }; } } @@ -374,10 +380,12 @@ class LoginHttp { var res = await Request().post( Api.safeCenterSmsCode, data: data, - options: - Options(contentType: Headers.formUrlEncodedContentType, headers: { - "Referer": refererUrl, - }), + options: Options( + contentType: Headers.formUrlEncodedContentType, + headers: { + "Referer": refererUrl, + }, + ), ); if (res.data['code'] == 0) { @@ -387,7 +395,7 @@ class LoginHttp { 'status': false, 'code': res.data['code'], 'msg': res.data['message'], - 'data': res.data['data'] + 'data': res.data['data'], }; } } @@ -414,10 +422,12 @@ class LoginHttp { var res = await Request().post( Api.safeCenterSmsVerify, data: data, - options: - Options(contentType: Headers.formUrlEncodedContentType, headers: { - "Referer": refererUrl, - }), + options: Options( + contentType: Headers.formUrlEncodedContentType, + headers: { + "Referer": refererUrl, + }, + ), ); if (res.data['code'] == 0) { @@ -427,7 +437,7 @@ class LoginHttp { 'status': false, 'code': res.data['code'], 'msg': res.data['message'], - 'data': res.data['data'] + 'data': res.data['data'], }; } } @@ -473,7 +483,7 @@ class LoginHttp { 'status': false, 'code': res.data['code'], 'msg': res.data['message'], - 'data': res.data['data'] + 'data': res.data['data'], }; } } @@ -483,8 +493,9 @@ class LoginHttp { Api.logout, data: {'biliCSRF': account.csrf}, options: Options( - contentType: Headers.formUrlEncodedContentType, - extra: {'account': account}), + contentType: Headers.formUrlEncodedContentType, + extra: {'account': account}, + ), ); return {'status': res.data['code'] == 0, 'msg': res.data['message']}; } diff --git a/lib/http/member.dart b/lib/http/member.dart index 9f930aece..84c812063 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -99,7 +99,8 @@ class MemberHttp { ); if (res.data['code'] == 0) { return Success( - SpaceSsData.fromJson(res.data['data']?['items_lists'] ?? {})); + SpaceSsData.fromJson(res.data['data']?['items_lists'] ?? {}), + ); } else { return Error(res.data['message']); } @@ -172,7 +173,7 @@ class MemberHttp { 'ps': 20, 'order': 1, 'uid': mid, - 'web_location': 333.1387 + 'web_location': 333.1387, }, ); if (res.data['code'] == 0) { @@ -286,7 +287,7 @@ class MemberHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': MemberInfoModel.fromJson(res.data['data']) + 'data': MemberInfoModel.fromJson(res.data['data']), }; } else { return {'status': false, 'msg': res.data['message']}; @@ -313,7 +314,7 @@ class MemberHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': MemberCardInfoData.fromJson(res.data['data']) + 'data': MemberCardInfoData.fromJson(res.data['data']), }; } else { return {'status': false, 'msg': res.data['message']}; @@ -349,11 +350,13 @@ class MemberHttp { var res = await Request().get( Api.searchArchive, queryParameters: params, - options: Options(headers: { - HttpHeaders.userAgentHeader: Request.headerUa(type: 'pc'), - HttpHeaders.refererHeader: '${HttpString.spaceBaseUrl}/$mid', - 'origin': HttpString.spaceBaseUrl, - }), + options: Options( + headers: { + HttpHeaders.userAgentHeader: Request.headerUa(type: 'pc'), + HttpHeaders.refererHeader: '${HttpString.spaceBaseUrl}/$mid', + 'origin': HttpString.spaceBaseUrl, + }, + ), ); if (res.data['code'] == 0) { return Success(SearchArchiveData.fromJson(res.data['data'])); @@ -465,7 +468,7 @@ class MemberHttp { 'status': true, 'data': res.data['data'] .map((e) => MemberTagItemModel.fromJson(e)) - .toList() + .toList(), }; } else { return {'status': false, 'msg': res.data['message']}; @@ -502,7 +505,7 @@ class MemberHttp { Api.addUsers, queryParameters: { 'x-bili-device-req-json': - '{"platform":"web","device":"pc","spmid":"333.1387"}' + '{"platform":"web","device":"pc","spmid":"333.1387"}', }, data: { 'fids': fids.join(','), @@ -538,10 +541,13 @@ class MemberHttp { }, ); if (res.data['code'] == 0) { - return Success(FollowData( + return Success( + FollowData( list: (res.data['data'] as List?) ?.map((e) => FollowItemModel.fromJson(e)) - .toList())); + .toList(), + ), + ); } else { return Error(res.data['message']); } @@ -622,7 +628,7 @@ class MemberHttp { 'status': true, 'data': res.data['data'] .map((e) => MemberTagItemModel.fromJson(e)) - .toList() + .toList(), }; } else { return {'status': false, 'msg': res.data['message']}; @@ -631,8 +637,10 @@ class MemberHttp { // 获取up播放数、点赞数 static Future memberView({required int mid}) async { - var res = await Request() - .get(Api.getMemberViewApi, queryParameters: {'mid': mid}); + var res = await Request().get( + Api.getMemberViewApi, + queryParameters: {'mid': mid}, + ); if (res.data['code'] == 0) { return {'status': true, 'data': res.data['data']}; } else { @@ -658,11 +666,14 @@ class MemberHttp { 'web_location': 333.999, }; Map params = await WbiSign.makSign(data); - var res = await Request().get(Api.followSearch, queryParameters: { - ...data, - 'w_rid': params['w_rid'], - 'wts': params['wts'], - }); + var res = await Request().get( + Api.followSearch, + queryParameters: { + ...data, + 'w_rid': params['w_rid'], + 'wts': params['wts'], + }, + ); if (res.data['code'] == 0) { return Success(FollowData.fromJson(res.data['data'])); } else { diff --git a/lib/http/msg.dart b/lib/http/msg.dart index 0d05bc969..99ff4af0a 100644 --- a/lib/http/msg.dart +++ b/lib/http/msg.dart @@ -41,8 +41,10 @@ class MsgHttp { } } - static Future> msgFeedAtMe( - {int? cursor, int? cursorTime}) async { + static Future> msgFeedAtMe({ + int? cursor, + int? cursorTime, + }) async { var res = await Request().get( Api.msgFeedAt, queryParameters: { @@ -61,16 +63,21 @@ class MsgHttp { } } - static Future> msgFeedLikeMe( - {int? cursor, int? cursorTime}) async { - var res = await Request().get(Api.msgFeedLike, queryParameters: { - 'id': ?cursor, - 'like_time': ?cursorTime, - 'platform': 'web', - 'mobi_app': 'web', - 'build': 0, - 'web_location': 333.40164, - }); + static Future> msgFeedLikeMe({ + int? cursor, + int? cursorTime, + }) async { + var res = await Request().get( + Api.msgFeedLike, + queryParameters: { + 'id': ?cursor, + 'like_time': ?cursorTime, + 'platform': 'web', + 'mobi_app': 'web', + 'build': 0, + 'web_location': 333.40164, + }, + ); if (res.data['code'] == 0) { return Success(MsgLikeData.fromJson(res.data['data'])); } else { @@ -101,8 +108,10 @@ class MsgHttp { } } - static Future?>> msgFeedNotify( - {int? cursor, int pageSize = 20}) async { + static Future?>> msgFeedNotify({ + int? cursor, + int pageSize = 20, + }) async { var res = await Request().get( Api.msgSysNotify, queryParameters: { @@ -114,9 +123,11 @@ class MsgHttp { }, ); if (res.data['code'] == 0) { - return Success((res.data['data'] as List?) - ?.map((e) => MsgSysItem.fromJson(e)) - .toList()); + return Success( + (res.data['data'] as List?) + ?.map((e) => MsgSysItem.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } @@ -124,10 +135,13 @@ class MsgHttp { static Future msgSysUpdateCursor(int cursor) async { String csrf = Accounts.main.csrf; - var res = await Request().get(Api.msgSysUpdateCursor, queryParameters: { - 'csrf': csrf, - 'cursor': cursor, - }); + var res = await Request().get( + Api.msgSysUpdateCursor, + queryParameters: { + 'csrf': csrf, + 'cursor': cursor, + }, + ); if (res.data['code'] == 0) { return { 'status': true, @@ -254,7 +268,7 @@ class MsgHttp { 'build': 0, 'mobi_app': 'web', 'csrf_token': csrf, - 'csrf': csrf + 'csrf': csrf, }); var res = await Request().post( HttpString.tUrl + Api.removeMsg, @@ -336,10 +350,12 @@ class MsgHttp { 'build': 0, 'mobi_app': 'web', 'csrf_token': csrf, - 'csrf': csrf + 'csrf': csrf, }); - var res = await Request() - .post(HttpString.tUrl + Api.setTop, data: FormData.fromMap(data)); + var res = await Request().post( + HttpString.tUrl + Api.setTop, + data: FormData.fromMap(data), + ); if (res.data['code'] == 0) { return {'status': true}; } else { @@ -363,7 +379,7 @@ class MsgHttp { 'build': 0, 'mobi_app': 'web', 'csrf_token': csrf, - 'csrf': csrf + 'csrf': csrf, }); var res = await Request().get(Api.ackSessionMsg, queryParameters: params); if (res.data['code'] == 0) { @@ -374,7 +390,8 @@ class MsgHttp { } else { return { 'status': false, - 'msg': "message: ${res.data['message']}," + 'msg': + "message: ${res.data['message']}," " msg: ${res.data['msg']}," " code: ${res.data['code']}", }; @@ -530,9 +547,11 @@ class MsgHttp { }, ); if (res.data['code'] == 0) { - return Success((res.data['data'] as List?) - ?.map((e) => ImUserInfosData.fromJson(e)) - .toList()); + return Success( + (res.data['data'] as List?) + ?.map((e) => ImUserInfosData.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } @@ -575,9 +594,11 @@ class MsgHttp { }, ); if (res.data['code'] == 0) { - return Success((res.data['data']?['uid_settings'] as List?) - ?.map((e) => UidSetting.fromJson(e)) - .toList()); + return Success( + (res.data['data']?['uid_settings'] as List?) + ?.map((e) => UidSetting.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } @@ -596,7 +617,7 @@ class MsgHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': SingleUnreadData.fromJson(res.data['data']) + 'data': SingleUnreadData.fromJson(res.data['data']), }; } else { return {'status': false, 'data': res.data['message']}; @@ -615,7 +636,7 @@ class MsgHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': MsgFeedUnreadData.fromJson(res.data['data']) + 'data': MsgFeedUnreadData.fromJson(res.data['data']), }; } else { return {'status': false, 'data': res.data['message']}; diff --git a/lib/http/reply.dart b/lib/http/reply.dart index 627c9400a..52155a05f 100644 --- a/lib/http/reply.dart +++ b/lib/http/reply.dart @@ -12,8 +12,9 @@ import 'package:PiliPlus/utils/accounts/account.dart'; import 'package:dio/dio.dart'; class ReplyHttp { - static final Options _options = - Options(extra: {'account': AnonymousAccount(), 'checkReply': true}); + static final Options _options = Options( + extra: {'account': AnonymousAccount(), 'checkReply': true}, + ); static Future replyList({ required bool isLogin, @@ -229,12 +230,16 @@ class ReplyHttp { } } - static Future?>> getEmoteList( - {String? business}) async { - var res = await Request().get(Api.myEmote, queryParameters: { - 'business': business ?? 'reply', - 'web_location': '333.1245', - }); + static Future?>> getEmoteList({ + String? business, + }) async { + var res = await Request().get( + Api.myEmote, + queryParameters: { + 'business': business ?? 'reply', + 'web_location': '333.1245', + }, + ); if (res.data['code'] == 0) { return Success(EmoteModelData.fromJson(res.data['data']).packages); } else { diff --git a/lib/http/retry_interceptor.dart b/lib/http/retry_interceptor.dart index 7ff72826d..53d24464d 100644 --- a/lib/http/retry_interceptor.dart +++ b/lib/http/retry_interceptor.dart @@ -29,9 +29,15 @@ class RetryInterceptor extends Interceptor { } Request.dio .fetch(options) - .then((i) => handler.resolve(i - ..redirects.add(RedirectRecord(status, options.method, uri)) - ..isRedirect = true)) + .then( + (i) => handler.resolve( + i + ..redirects.add( + RedirectRecord(status, options.method, uri), + ) + ..isRedirect = true, + ), + ) .onError((error, _) => handler.next(error)); return; } @@ -46,13 +52,14 @@ class RetryInterceptor extends Interceptor { case DioExceptionType.unknown: if ((err.requestOptions.extra['_rt'] ??= 0) < _count) { Future.delayed( - Duration( - milliseconds: ++err.requestOptions.extra['_rt'] * _delay), - () => Request.dio - .fetch(err.requestOptions) - .then(handler.resolve) - .onError( - (error, _) => handler.reject(error))); + Duration( + milliseconds: ++err.requestOptions.extra['_rt'] * _delay, + ), + () => Request.dio + .fetch(err.requestOptions) + .then(handler.resolve) + .onError((error, _) => handler.reject(error)), + ); } else { handler.next(err); } diff --git a/lib/http/search.dart b/lib/http/search.dart index 6f1a8bb3b..31c840519 100644 --- a/lib/http/search.dart +++ b/lib/http/search.dart @@ -175,8 +175,10 @@ class SearchHttp { } } - static Future> pgcInfoNew( - {int? seasonId, int? epId}) async { + static Future> pgcInfoNew({ + int? seasonId, + int? epId, + }) async { var res = await Request().get( Api.pgcInfo, queryParameters: { @@ -226,8 +228,9 @@ class SearchHttp { } } - static Future> searchTrending( - {int limit = 30}) async { + static Future> searchTrending({ + int limit = 30, + }) async { final res = await Request().get( Api.searchTrending, queryParameters: { diff --git a/lib/http/user.dart b/lib/http/user.dart index e78f13d2e..0d67cfe8f 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -81,12 +81,15 @@ class UserHttp { int? max, int? viewAt, }) async { - var res = await Request().get(Api.historyList, queryParameters: { - 'type': type, - 'ps': 20, - 'max': max ?? 0, - 'view_at': viewAt ?? 0, - }); + var res = await Request().get( + Api.historyList, + queryParameters: { + 'type': type, + 'ps': 20, + 'max': max ?? 0, + 'view_at': viewAt ?? 0, + }, + ); if (res.data['code'] == 0) { return Success(HistoryData.fromJson(res.data['data'])); } else { @@ -151,7 +154,7 @@ class UserHttp { static Future toViewDel({required List aids}) async { final Map params = { 'csrf': Accounts.main.csrf, - 'resources': aids.join(',') + 'resources': aids.join(','), }; var res = await Request().post( Api.toViewDel, @@ -235,8 +238,10 @@ class UserHttp { } // 搜索历史记录 - static Future> searchHistory( - {required int pn, required String keyword}) async { + static Future> searchHistory({ + required int pn, + required String keyword, + }) async { var res = await Request().get( Api.searchHistory, queryParameters: { @@ -275,8 +280,10 @@ class UserHttp { } static Future> videoTags({required String bvid}) async { - var res = - await Request().get(Api.videoTags, queryParameters: {'bvid': bvid}); + var res = await Request().get( + Api.videoTags, + queryParameters: {'bvid': bvid}, + ); if (res.data['code'] == 0) { List? list = (res.data['data'] as List?) ?.map((e) => VideoTagItem.fromJson(e)) diff --git a/lib/http/video.dart b/lib/http/video.dart index 66fa2b0f2..3f8208efb 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -39,8 +39,10 @@ class VideoHttp { static bool enableFilter = zoneRegExp.pattern.isNotEmpty; // 首页推荐视频 - static Future rcmdVideoList( - {required int ps, required int freshIdx}) async { + static Future rcmdVideoList({ + required int ps, + required int freshIdx, + }) async { var res = await Request().get( Api.recommendListWeb, queryParameters: { @@ -50,7 +52,7 @@ class VideoHttp { 'ps': ps, 'fresh_idx': freshIdx, 'brush': freshIdx, - 'fresh_type': 4 + 'fresh_type': 4, }, ); if (res.data['code'] == 0) { @@ -101,26 +103,28 @@ class VideoHttp { 's_locale': 'zh_CN', 'splash_id': '', 'statistics': Constants.statistics, - 'voice_balance': '0' + 'voice_balance': '0', }; var res = await Request().get( Api.recommendListApp, queryParameters: data, - options: Options(headers: { - 'buvid': LoginHttp.buvid, - 'fp_local': - '1111111111111111111111111111111111111111111111111111111111111111', - 'fp_remote': - '1111111111111111111111111111111111111111111111111111111111111111', - 'session_id': '11111111', - 'env': 'prod', - 'app-key': 'android_hd', - 'User-Agent': Constants.userAgent, - 'x-bili-trace-id': Constants.traceId, - 'x-bili-aurora-eid': '', - 'x-bili-aurora-zone': '', - 'bili-http-engine': 'cronet', - }), + options: Options( + headers: { + 'buvid': LoginHttp.buvid, + 'fp_local': + '1111111111111111111111111111111111111111111111111111111111111111', + 'fp_remote': + '1111111111111111111111111111111111111111111111111111111111111111', + 'session_id': '11111111', + 'env': 'prod', + 'app-key': 'android_hd', + 'User-Agent': Constants.userAgent, + 'x-bili-trace-id': Constants.traceId, + 'x-bili-aurora-eid': '', + 'x-bili-aurora-zone': '', + 'bili-http-engine': 'cronet', + }, + ), ); if (res.data['code'] == 0) { List list = []; @@ -150,8 +154,10 @@ class VideoHttp { } // 最热视频 - static Future>> hotVideoList( - {required int pn, required int ps}) async { + static Future>> hotVideoList({ + required int pn, + required int ps, + }) async { var res = await Request().get( Api.hotList, queryParameters: {'pn': pn, 'ps': ps}, @@ -162,7 +168,9 @@ class VideoHttp { if (!GlobalData().blackMids.contains(i['owner']['mid']) && !RecommendFilter.filterTitle(i['title']) && !RecommendFilter.filterLikeRatio( - i['stat']['like'], i['stat']['view'])) { + i['stat']['like'], + i['stat']['view'], + )) { if (enableFilter && i['tname'] != null && zoneRegExp.hasMatch(i['tname'])) { @@ -219,8 +227,8 @@ class VideoHttp { late PlayUrlModel data; if (epid != null && usePgcApi) { data = PlayUrlModel.fromJson(res.data['result']['video_info']) - ..lastPlayTime = res.data['result']['play_view_business_info'] - ['user_status']['watch_progress']['current_watch_progress']; + ..lastPlayTime = res + .data['result']['play_view_business_info']['user_status']['watch_progress']['current_watch_progress']; } else { data = PlayUrlModel.fromJson(res.data['data']); } @@ -252,10 +260,13 @@ class VideoHttp { } // 视频信息 标题、简介 - static Future> videoIntro( - {required String bvid}) async { - var res = - await Request().get(Api.videoIntro, queryParameters: {'bvid': bvid}); + static Future> videoIntro({ + required String bvid, + }) async { + var res = await Request().get( + Api.videoIntro, + queryParameters: {'bvid': bvid}, + ); VideoDetailResponse data = VideoDetailResponse.fromJson(res.data); if (data.code == 0) { return Success(data.data!); @@ -286,13 +297,17 @@ class VideoHttp { } // 相关视频 - static Future?>> relatedVideoList( - {required String bvid}) async { - var res = - await Request().get(Api.relatedList, queryParameters: {'bvid': bvid}); + static Future?>> relatedVideoList({ + required String bvid, + }) async { + var res = await Request().get( + Api.relatedList, + queryParameters: {'bvid': bvid}, + ); if (res.data['code'] == 0) { - final items = (res.data['data'] as List?) - ?.map((i) => HotVideoItemModel.fromJson(i)); + final items = (res.data['data'] as List?)?.map( + (i) => HotVideoItemModel.fromJson(i), + ); final list = RecommendFilter.applyFilterToRelatedVideos ? items?.where((i) => !RecommendFilter.filterAll(i)).toList() : items?.toList(); @@ -426,29 +441,33 @@ class VideoHttp { } else { return { 'status': false, - 'msg': res.data is String ? res.data : res.data['message'] + 'msg': res.data is String ? res.data : res.data['message'], }; } } // 推送不感兴趣反馈 - static Future feedDislike( - {required String goto, - required int id, - int? reasonId, - int? feedbackId}) async { + static Future feedDislike({ + required String goto, + required int id, + int? reasonId, + int? feedbackId, + }) async { if (Accounts.get(AccountType.recommend).accessKey.isNullOrEmpty) { return {'status': false, 'msg': "请退出账号后重新登录"}; } assert((reasonId != null) ^ (feedbackId != null)); - var res = await Request().get(Api.feedDislike, queryParameters: { - 'goto': goto, - 'id': id, - 'reason_id': ?reasonId, - 'feedback_id': ?feedbackId, - 'build': '1', - 'mobi_app': 'android', - }); + var res = await Request().get( + Api.feedDislike, + queryParameters: { + 'goto': goto, + 'id': id, + 'reason_id': ?reasonId, + 'feedback_id': ?feedbackId, + 'build': '1', + 'mobi_app': 'android', + }, + ); if (res.data['code'] == 0) { return {'status': true}; } else { @@ -457,22 +476,26 @@ class VideoHttp { } // 推送不感兴趣取消 - static Future feedDislikeCancel( - {required String goto, - required int id, - int? reasonId, - int? feedbackId}) async { + static Future feedDislikeCancel({ + required String goto, + required int id, + int? reasonId, + int? feedbackId, + }) async { if (Accounts.get(AccountType.recommend).accessKey.isNullOrEmpty) { return {'status': false, 'msg': "请退出账号后重新登录"}; } - var res = await Request().get(Api.feedDislikeCancel, queryParameters: { - 'goto': goto, - 'id': id, - 'reason_id': ?reasonId, - 'feedback_id': ?feedbackId, - 'build': '1', - 'mobi_app': 'android', - }); + var res = await Request().get( + Api.feedDislikeCancel, + queryParameters: { + 'goto': goto, + 'id': id, + 'reason_id': ?reasonId, + 'feedback_id': ?feedbackId, + 'build': '1', + 'mobi_app': 'android', + }, + ); if (res.data['code'] == 0) { return {'status': true}; } else { @@ -531,12 +554,15 @@ class VideoHttp { required int oid, required int rpid, }) async { - var res = await Request().post(Api.replyDel, queryParameters: { - 'type': type, //type.index - 'oid': oid, - 'rpid': rpid, - 'csrf': Accounts.main.csrf, - }); + var res = await Request().post( + Api.replyDel, + queryParameters: { + 'type': type, //type.index + 'oid': oid, + 'rpid': rpid, + 'csrf': Accounts.main.csrf, + }, + ); log(res.toString()); if (res.data['code'] == 0) { return {'status': true}; @@ -546,8 +572,11 @@ class VideoHttp { } // 操作用户关系 - static Future relationMod( - {required int mid, required int act, required int reSrc}) async { + static Future relationMod({ + required int mid, + required int act, + required int reSrc, + }) async { var res = await Request().post( Api.relationMod, queryParameters: { @@ -603,11 +632,14 @@ class VideoHttp { aid, type, }) async { - await Request().post(Api.historyReport, queryParameters: { - 'aid': ?aid, - 'type': ?type, - 'csrf': Accounts.main.csrf, - }); + await Request().post( + Api.historyReport, + queryParameters: { + 'aid': ?aid, + 'type': ?type, + 'csrf': Accounts.main.csrf, + }, + ); } // 视频播放进度 @@ -619,16 +651,19 @@ class VideoHttp { seasonId, subType, }) async { - await Request().post(Api.heartBeat, queryParameters: { - 'bvid': bvid, - 'cid': cid, - 'epid': ?epid, - 'sid': ?seasonId, - if (epid != null) 'type': 4, - 'sub_type': ?subType, - 'played_time': progress, - 'csrf': Accounts.main.csrf, - }); + await Request().post( + Api.heartBeat, + queryParameters: { + 'bvid': bvid, + 'cid': cid, + 'epid': ?epid, + 'sid': ?seasonId, + if (epid != null) 'type': 4, + 'sub_type': ?subType, + 'played_time': progress, + 'csrf': Accounts.main.csrf, + }, + ); } static Future medialistHistory({ @@ -636,52 +671,65 @@ class VideoHttp { required dynamic oid, required dynamic upperMid, }) async { - await Request().post(Api.mediaListHistory, queryParameters: { - 'desc': desc, - 'oid': oid, - 'upper_mid': upperMid, - 'csrf': Accounts.main.csrf, - }); + await Request().post( + Api.mediaListHistory, + queryParameters: { + 'desc': desc, + 'oid': oid, + 'upper_mid': upperMid, + 'csrf': Accounts.main.csrf, + }, + ); } // 添加追番 static Future pgcAdd({int? seasonId}) async { - var res = await Request().post(Api.pgcAdd, queryParameters: { - 'season_id': seasonId, - 'csrf': Accounts.main.csrf, - }); + var res = await Request().post( + Api.pgcAdd, + queryParameters: { + 'season_id': seasonId, + 'csrf': Accounts.main.csrf, + }, + ); if (res.data['code'] == 0) { return { 'status': true, - 'msg': - res.data['result'] == null ? 'failed' : res.data['result']['toast'] + 'msg': res.data['result'] == null + ? 'failed' + : res.data['result']['toast'], }; } else { return { 'status': false, - 'msg': - res.data['result'] == null ? 'failed' : res.data['result']['toast'] + 'msg': res.data['result'] == null + ? 'failed' + : res.data['result']['toast'], }; } } // 取消追番 static Future pgcDel({int? seasonId}) async { - var res = await Request().post(Api.pgcDel, queryParameters: { - 'season_id': seasonId, - 'csrf': Accounts.main.csrf, - }); + var res = await Request().post( + Api.pgcDel, + queryParameters: { + 'season_id': seasonId, + 'csrf': Accounts.main.csrf, + }, + ); if (res.data['code'] == 0) { return { 'status': true, - 'msg': - res.data['result'] == null ? 'failed' : res.data['result']['toast'] + 'msg': res.data['result'] == null + ? 'failed' + : res.data['result']['toast'], }; } else { return { 'status': false, - 'msg': - res.data['result'] == null ? 'failed' : res.data['result']['toast'] + 'msg': res.data['result'] == null + ? 'failed' + : res.data['result']['toast'], }; } } @@ -703,17 +751,22 @@ class VideoHttp { ); return { 'status': res.data['code'] == 0, - 'msg': res.data['result'] == null ? 'failed' : res.data['result']['toast'] + 'msg': res.data['result'] == null + ? 'failed' + : res.data['result']['toast'], }; } // 查看视频同时在看人数 static Future onlineTotal({int? aid, String? bvid, int? cid}) async { - var res = await Request().get(Api.onlineTotal, queryParameters: { - 'aid': aid, - 'bvid': bvid, - 'cid': cid, - }); + var res = await Request().get( + Api.onlineTotal, + queryParameters: { + 'aid': aid, + 'bvid': bvid, + 'cid': cid, + }, + ); if (res.data['code'] == 0) { return {'status': true, 'data': res.data['data']['total']}; } else { @@ -777,9 +830,12 @@ class VideoHttp { String processList(List list) { final sb = StringBuffer('WEBVTT\n\n') ..writeAll( - list.map((item) => - '${item?['sid'] ?? 0}\n${subtitleTimecode(item['from'])} --> ${subtitleTimecode(item['to'])}\n${item['content'].trim()}'), - '\n\n'); + list.map( + (item) => + '${item?['sid'] ?? 0}\n${subtitleTimecode(item['from'])} --> ${subtitleTimecode(item['to'])}\n${item['content'].trim()}', + ), + '\n\n', + ); return sb.toString(); } @@ -793,7 +849,8 @@ class VideoHttp { // 视频排行 static Future>> getRankVideoList( - int rid) async { + int rid, + ) async { var res = await Request().get( Api.getRankApi, queryParameters: await WbiSign.makSign({ @@ -807,7 +864,9 @@ class VideoHttp { if (!GlobalData().blackMids.contains(i['owner']['mid']) && !RecommendFilter.filterTitle(i['title']) && !RecommendFilter.filterLikeRatio( - i['stat']['like'], i['stat']['view'])) { + i['stat']['like'], + i['stat']['view'], + )) { if (enableFilter && i['tname'] != null && zoneRegExp.hasMatch(i['tname'])) { @@ -823,8 +882,10 @@ class VideoHttp { } // pgc 排行 - static Future pgcRankList( - {int day = 3, required int seasonType}) async { + static Future pgcRankList({ + int day = 3, + required int seasonType, + }) async { var res = await Request().get( Api.pgcRank, queryParameters: await WbiSign.makSign({ @@ -833,17 +894,21 @@ class VideoHttp { }), ); if (res.data['code'] == 0) { - return Success((res.data['result']?['list'] as List?) - ?.map((e) => PgcRankItemModel.fromJson(e)) - .toList()); + return Success( + (res.data['result']?['list'] as List?) + ?.map((e) => PgcRankItemModel.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } } // pgc season 排行 - static Future pgcSeasonRankList( - {int day = 3, required int seasonType}) async { + static Future pgcSeasonRankList({ + int day = 3, + required int seasonType, + }) async { var res = await Request().get( Api.pgcSeasonRank, queryParameters: await WbiSign.makSign({ @@ -852,9 +917,11 @@ class VideoHttp { }), ); if (res.data['code'] == 0) { - return Success((res.data['data']?['list'] as List?) - ?.map((e) => PgcRankItemModel.fromJson(e)) - .toList()); + return Success( + (res.data['data']?['list'] as List?) + ?.map((e) => PgcRankItemModel.fromJson(e)) + .toList(), + ); } else { return Error(res.data['message']); } diff --git a/lib/main.dart b/lib/main.dart index ea1498f19..fe5aa3b9c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -71,7 +71,8 @@ void main() async { if (Pref.enableLog) { // 异常捕获 logo记录 - String buildConfig = '''\n + String buildConfig = + '''\n Build Time: ${DateUtil.format(BuildConfig.buildTime, format: DateUtil.longFormatDs)} Commit Hash: ${BuildConfig.commitHash}'''; final Catcher2Options debugConfig = Catcher2Options( @@ -82,7 +83,7 @@ Commit Hash: ${BuildConfig.commitHash}'''; enableDeviceParameters: false, enableApplicationParameters: false, enableCustomParameters: true, - ) + ), ], customParameters: { 'BuildConfig': buildConfig, @@ -95,7 +96,7 @@ Commit Hash: ${BuildConfig.commitHash}'''; FileHandler(await getLogsPath()), ConsoleHandler( enableCustomParameters: true, - ) + ), ], customParameters: { 'BuildConfig': buildConfig, @@ -115,12 +116,14 @@ Commit Hash: ${BuildConfig.commitHash}'''; // 小白条、导航栏沉浸 SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( - systemNavigationBarColor: Colors.transparent, - systemNavigationBarDividerColor: Colors.transparent, - statusBarColor: Colors.transparent, - systemNavigationBarContrastEnforced: false, - )); + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + systemNavigationBarColor: Colors.transparent, + systemNavigationBarDividerColor: Colors.transparent, + statusBarColor: Colors.transparent, + systemNavigationBarContrastEnforced: false, + ), + ); Data.init(); PiliScheme.init(); } @@ -144,8 +147,10 @@ class MyApp extends StatelessWidget { var storageDisplay = GStorage.setting.get(SettingBoxKey.displayMode); DisplayMode f = DisplayMode.auto; if (storageDisplay != null) { - f = modes.firstWhere((e) => e.toString() == storageDisplay, - orElse: () => f); + f = modes.firstWhere( + (e) => e.toString() == storageDisplay, + orElse: () => f, + ); } DisplayMode preferred = modes.toList().firstWhere((el) => el == f); FlutterDisplayMode.setPreferredMode(preferred); @@ -211,7 +216,8 @@ class MyApp extends StatelessWidget { builder: (context, child) { return MediaQuery( data: MediaQuery.of(context).copyWith( - textScaler: TextScaler.linear(Pref.defaultTextScale)), + textScaler: TextScaler.linear(Pref.defaultTextScale), + ), child: child!, ); }, diff --git a/lib/member_card_info/card.dart b/lib/member_card_info/card.dart index c6515acac..a14d56cd1 100644 --- a/lib/member_card_info/card.dart +++ b/lib/member_card_info/card.dart @@ -20,17 +20,18 @@ class Card { }); factory Card.fromJson(Map json) => Card( - mid: json['mid'] as String?, - name: json['name'] as String?, - face: json['face'] as String?, - fans: json['fans'] as int?, - attention: json['attention'] as int?, - officialVerify: json['official_verify'] == null - ? null - : BaseOfficialVerify.fromJson( - json['official_verify'] as Map), - vip: json['vip'] == null - ? null - : Vip.fromJson(json['vip'] as Map), - ); + mid: json['mid'] as String?, + name: json['name'] as String?, + face: json['face'] as String?, + fans: json['fans'] as int?, + attention: json['attention'] as int?, + officialVerify: json['official_verify'] == null + ? null + : BaseOfficialVerify.fromJson( + json['official_verify'] as Map, + ), + vip: json['vip'] == null + ? null + : Vip.fromJson(json['vip'] as Map), + ); } diff --git a/lib/models/common/dm_block_type.dart b/lib/models/common/dm_block_type.dart index cee31e94b..9924df1fb 100644 --- a/lib/models/common/dm_block_type.dart +++ b/lib/models/common/dm_block_type.dart @@ -1,8 +1,7 @@ enum DmBlockType { keyword('关键词'), regex('正则'), - uid('用户'), - ; + uid('用户'); final String label; const DmBlockType(this.label); diff --git a/lib/models/common/dynamic/dynamic_badge_mode.dart b/lib/models/common/dynamic/dynamic_badge_mode.dart index 9ce018d6b..044c6e9ec 100644 --- a/lib/models/common/dynamic/dynamic_badge_mode.dart +++ b/lib/models/common/dynamic/dynamic_badge_mode.dart @@ -1,8 +1,7 @@ enum DynamicBadgeMode { hidden('隐藏'), point('红点'), - number('数字'), - ; + number('数字'); final String desc; const DynamicBadgeMode(this.desc); diff --git a/lib/models/common/dynamic/dynamics_type.dart b/lib/models/common/dynamic/dynamics_type.dart index a2c397422..dc71a080d 100644 --- a/lib/models/common/dynamic/dynamics_type.dart +++ b/lib/models/common/dynamic/dynamics_type.dart @@ -3,8 +3,7 @@ enum DynamicsTabType { video('投稿'), pgc('番剧'), article('专栏'), - up('UP'), - ; + up('UP'); final String label; const DynamicsTabType(this.label); diff --git a/lib/models/common/fav_order_type.dart b/lib/models/common/fav_order_type.dart index e6f7b4d64..3ad6990eb 100644 --- a/lib/models/common/fav_order_type.dart +++ b/lib/models/common/fav_order_type.dart @@ -1,8 +1,7 @@ enum FavOrderType { mtime('最近收藏'), view('最多播放'), - pubtime('最近投稿'), - ; + pubtime('最近投稿'); final String label; diff --git a/lib/models/common/home_tab_type.dart b/lib/models/common/home_tab_type.dart index 40d7d6e09..1f7e88b16 100644 --- a/lib/models/common/home_tab_type.dart +++ b/lib/models/common/home_tab_type.dart @@ -26,21 +26,21 @@ enum HomeTabType implements EnumWithLabel { const HomeTabType(this.label); ScrollOrRefreshMixin Function() get ctr => switch (this) { - HomeTabType.live => Get.find, - HomeTabType.rcmd => Get.find, - HomeTabType.hot => Get.find, - HomeTabType.rank => - (Get.find) as ScrollOrRefreshMixin Function(), - HomeTabType.bangumi || HomeTabType.cinema => () => - Get.find(tag: name), - }; + HomeTabType.live => Get.find, + HomeTabType.rcmd => Get.find, + HomeTabType.hot => Get.find, + HomeTabType.rank => + (Get.find) as ScrollOrRefreshMixin Function(), + HomeTabType.bangumi || + HomeTabType.cinema => () => Get.find(tag: name), + }; Widget get page => switch (this) { - HomeTabType.live => const LivePage(), - HomeTabType.rcmd => const RcmdPage(), - HomeTabType.hot => const HotPage(), - HomeTabType.rank => const RankPage(), - HomeTabType.bangumi => const PgcPage(tabType: HomeTabType.bangumi), - HomeTabType.cinema => const PgcPage(tabType: HomeTabType.cinema), - }; + HomeTabType.live => const LivePage(), + HomeTabType.rcmd => const RcmdPage(), + HomeTabType.hot => const HotPage(), + HomeTabType.rank => const RankPage(), + HomeTabType.bangumi => const PgcPage(tabType: HomeTabType.bangumi), + HomeTabType.cinema => const PgcPage(tabType: HomeTabType.cinema), + }; } diff --git a/lib/models/common/later_view_type.dart b/lib/models/common/later_view_type.dart index bcd7be2fa..1012e1222 100644 --- a/lib/models/common/later_view_type.dart +++ b/lib/models/common/later_view_type.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; enum LaterViewType { all(0, '全部'), // toView(1, '未看'), - unfinished(2, '未看完'), + unfinished(2, '未看完') // viewed(3, '已看完'), ; diff --git a/lib/models/common/member/tab_type.dart b/lib/models/common/member/tab_type.dart index 53a9fe950..a174362d6 100644 --- a/lib/models/common/member/tab_type.dart +++ b/lib/models/common/member/tab_type.dart @@ -4,8 +4,7 @@ enum MemberTabType { dynamic('动态'), contribute('投稿'), favorite('收藏'), - bangumi('番剧'), - ; + bangumi('番剧'); final String title; const MemberTabType(this.title); diff --git a/lib/models/common/reply/reply_option_type.dart b/lib/models/common/reply/reply_option_type.dart index e5a6e988b..858370b97 100644 --- a/lib/models/common/reply/reply_option_type.dart +++ b/lib/models/common/reply/reply_option_type.dart @@ -4,15 +4,14 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart enum ReplyOptionType { allow('允许评论'), close('关闭评论'), - choose('精选评论'), - ; + choose('精选评论'); final String title; const ReplyOptionType(this.title); IconData get iconData => switch (this) { - ReplyOptionType.allow => MdiIcons.commentTextOutline, - ReplyOptionType.close => MdiIcons.commentOffOutline, - ReplyOptionType.choose => MdiIcons.commentProcessingOutline - }; + ReplyOptionType.allow => MdiIcons.commentTextOutline, + ReplyOptionType.close => MdiIcons.commentOffOutline, + ReplyOptionType.choose => MdiIcons.commentProcessingOutline, + }; } diff --git a/lib/models/common/sponsor_block/action_type.dart b/lib/models/common/sponsor_block/action_type.dart index 6a73a1337..d7becd4e0 100644 --- a/lib/models/common/sponsor_block/action_type.dart +++ b/lib/models/common/sponsor_block/action_type.dart @@ -2,8 +2,7 @@ enum ActionType { skip('跳过'), mute('静音'), full('整个视频'), - poi('精彩时刻'), - ; + poi('精彩时刻'); final String title; const ActionType(this.title); diff --git a/lib/models/common/sponsor_block/segment_type.dart b/lib/models/common/sponsor_block/segment_type.dart index 958fe8d47..edc997869 100644 --- a/lib/models/common/sponsor_block/segment_type.dart +++ b/lib/models/common/sponsor_block/segment_type.dart @@ -14,7 +14,7 @@ enum SegmentType { music_offtopic, poi_highlight, filler, - exclusive_access + exclusive_access, } // List _actionType2SegmentType(ActionType actionType) { @@ -52,93 +52,93 @@ enum SegmentType { extension SegmentTypeExt on SegmentType { /// from https://github.com/hanydd/BilibiliSponsorBlock/blob/master/public/_locales/zh_CN/messages.json String get title => const [ - '赞助广告', //sponsor - '无偿/自我推广', //selfpromo - '三连/订阅提醒', //interaction - '过场/开场动画', //intro - '鸣谢/结束画面', //outro - '回顾/概要', //preview - '音乐:非音乐部分', //music_offtopic - '精彩时刻/重点', //poi_highlight - '离题闲聊/玩笑', //filler - '柔性推广/品牌合作', //exclusive_access - ][index]; + '赞助广告', //sponsor + '无偿/自我推广', //selfpromo + '三连/订阅提醒', //interaction + '过场/开场动画', //intro + '鸣谢/结束画面', //outro + '回顾/概要', //preview + '音乐:非音乐部分', //music_offtopic + '精彩时刻/重点', //poi_highlight + '离题闲聊/玩笑', //filler + '柔性推广/品牌合作', //exclusive_access + ][index]; String get shortTitle => const [ - '赞助广告', //sponsor - '推广', //selfpromo - '订阅提醒', //interaction - '开场', //intro - '片尾', //outro - '预览', //preview - '非音乐', //music_offtopic - '精彩时刻', //poi_highlight - '闲聊', //filler - '品牌合作', //exclusive_access - ][index]; + '赞助广告', //sponsor + '推广', //selfpromo + '订阅提醒', //interaction + '开场', //intro + '片尾', //outro + '预览', //preview + '非音乐', //music_offtopic + '精彩时刻', //poi_highlight + '闲聊', //filler + '品牌合作', //exclusive_access + ][index]; String get description => const [ - '付费推广、付费推荐和直接广告。不是自我推广或免费提及他们喜欢的商品/创作者/网站/产品。', //sponsor - '类似于 “赞助广告” ,但无报酬或是自我推广。包括有关商品、捐赠的部分或合作者的信息。', //selfpromo - '视频中间简短提醒观众来一键三连或关注。 如果片段较长,或是有具体内容,则应分类为自我推广。', //interaction - '没有实际内容的间隔片段。可以是暂停、静态帧或重复动画。不适用于包含内容的过场。', //intro - '致谢画面或片尾画面。不包含内容的结尾。', //outro - '展示此视频或同系列视频将出现的画面集锦,片段中所有内容都将在之后的正片中再次出现。', //preview - '仅用于音乐视频。此分类只能用于音乐视频中未包括于其他分类的部分。', //music_offtopic - '大部分人都在寻找的空降时间。类似于“封面在12:34”的评论。', //poi_highlight - "仅作为填充内容或增添趣味而添加的离题片段,这些内容对理解视频的主要内容并非必需。这不包括提供背景信息或上下文的片段。这是一个非常激进的分类,适用于当你不想看'娱乐性'内容的时候。", //filler - '仅用于对整个视频进行标记。适用于展示UP主免费或获得补贴后使用的产品、服务或场地的视频。', //exclusive_access - ][index]; + '付费推广、付费推荐和直接广告。不是自我推广或免费提及他们喜欢的商品/创作者/网站/产品。', //sponsor + '类似于 “赞助广告” ,但无报酬或是自我推广。包括有关商品、捐赠的部分或合作者的信息。', //selfpromo + '视频中间简短提醒观众来一键三连或关注。 如果片段较长,或是有具体内容,则应分类为自我推广。', //interaction + '没有实际内容的间隔片段。可以是暂停、静态帧或重复动画。不适用于包含内容的过场。', //intro + '致谢画面或片尾画面。不包含内容的结尾。', //outro + '展示此视频或同系列视频将出现的画面集锦,片段中所有内容都将在之后的正片中再次出现。', //preview + '仅用于音乐视频。此分类只能用于音乐视频中未包括于其他分类的部分。', //music_offtopic + '大部分人都在寻找的空降时间。类似于“封面在12:34”的评论。', //poi_highlight + "仅作为填充内容或增添趣味而添加的离题片段,这些内容对理解视频的主要内容并非必需。这不包括提供背景信息或上下文的片段。这是一个非常激进的分类,适用于当你不想看'娱乐性'内容的时候。", //filler + '仅用于对整个视频进行标记。适用于展示UP主免费或获得补贴后使用的产品、服务或场地的视频。', //exclusive_access + ][index]; Color get color => const [ - Color(0xFF00d400), //sponsor - Color(0xFFffff00), //selfpromo - Color(0xFFcc00ff), //interaction - Color(0xFF00ffff), //intro - Color(0xFF0202ed), //outro - Color(0xFF008fd6), //preview - Color(0xFFff9900), //music_offtopic - Color(0xFFff1684), //poi_highlight - Color(0xFF7300FF), //filler - Color(0xFF008a5c), //exclusive_access - ][index]; + Color(0xFF00d400), //sponsor + Color(0xFFffff00), //selfpromo + Color(0xFFcc00ff), //interaction + Color(0xFF00ffff), //intro + Color(0xFF0202ed), //outro + Color(0xFF008fd6), //preview + Color(0xFFff9900), //music_offtopic + Color(0xFFff1684), //poi_highlight + Color(0xFF7300FF), //filler + Color(0xFF008a5c), //exclusive_access + ][index]; List get toActionType { return switch (this) { SegmentType.sponsor => const [ - ActionType.skip, - ActionType.mute, - ActionType.full - ], + ActionType.skip, + ActionType.mute, + ActionType.full, + ], SegmentType.selfpromo => const [ - ActionType.skip, - ActionType.mute, - ActionType.full - ], + ActionType.skip, + ActionType.mute, + ActionType.full, + ], SegmentType.interaction => const [ - ActionType.skip, - ActionType.mute, - ], + ActionType.skip, + ActionType.mute, + ], SegmentType.intro => const [ - ActionType.skip, - ActionType.mute, - ], + ActionType.skip, + ActionType.mute, + ], SegmentType.outro => const [ - ActionType.skip, - ActionType.mute, - ], + ActionType.skip, + ActionType.mute, + ], SegmentType.preview => const [ - ActionType.skip, - ActionType.mute, - ], + ActionType.skip, + ActionType.mute, + ], SegmentType.music_offtopic => const [ - ActionType.skip, - ], + ActionType.skip, + ], SegmentType.poi_highlight => const [ActionType.poi], SegmentType.filler => const [ - ActionType.skip, - ActionType.mute, - ], + ActionType.skip, + ActionType.mute, + ], SegmentType.exclusive_access => const [ActionType.full], }; } diff --git a/lib/models/common/sponsor_block/skip_type.dart b/lib/models/common/sponsor_block/skip_type.dart index 6fd9a4c51..e66646e7d 100644 --- a/lib/models/common/sponsor_block/skip_type.dart +++ b/lib/models/common/sponsor_block/skip_type.dart @@ -3,8 +3,7 @@ enum SkipType { skipOnce('跳过一次'), skipManually('手动跳过'), showOnly('仅显示'), - disable('禁用'), - ; + disable('禁用'); final String title; const SkipType(this.title); diff --git a/lib/models/common/stat_type.dart b/lib/models/common/stat_type.dart index cc3943a4d..d43eaa886 100644 --- a/lib/models/common/stat_type.dart +++ b/lib/models/common/stat_type.dart @@ -7,8 +7,7 @@ enum StatType { reply(Icons.comment_outlined), follow(Icons.favorite_border), play(Icons.play_circle_outlined), - listen(Icons.headset_outlined), - ; + listen(Icons.headset_outlined); final IconData iconData; const StatType(this.iconData); diff --git a/lib/models/common/theme/theme_type.dart b/lib/models/common/theme/theme_type.dart index ffa91a681..9a301a491 100644 --- a/lib/models/common/theme/theme_type.dart +++ b/lib/models/common/theme/theme_type.dart @@ -4,21 +4,20 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart enum ThemeType { light('浅色'), dark('深色'), - system('跟随系统'), - ; + system('跟随系统'); final String desc; const ThemeType(this.desc); ThemeMode get toThemeMode => switch (this) { - ThemeType.light => ThemeMode.light, - ThemeType.dark => ThemeMode.dark, - ThemeType.system => ThemeMode.system, - }; + ThemeType.light => ThemeMode.light, + ThemeType.dark => ThemeMode.dark, + ThemeType.system => ThemeMode.system, + }; Icon get icon => switch (this) { - ThemeType.light => const Icon(MdiIcons.weatherSunny, size: 24), - ThemeType.dark => const Icon(MdiIcons.weatherNight, size: 24), - ThemeType.system => const Icon(MdiIcons.themeLightDark, size: 24), - }; + ThemeType.light => const Icon(MdiIcons.weatherSunny, size: 24), + ThemeType.dark => const Icon(MdiIcons.weatherNight, size: 24), + ThemeType.system => const Icon(MdiIcons.themeLightDark, size: 24), + }; } diff --git a/lib/models/common/video/live_quality.dart b/lib/models/common/video/live_quality.dart index d0fb008d4..f1ee04ccb 100644 --- a/lib/models/common/video/live_quality.dart +++ b/lib/models/common/video/live_quality.dart @@ -29,12 +29,12 @@ extension LiveQualityExt on LiveQuality { } String get description => const [ - '杜比', - '4K', - '原画', - '蓝光', - '超清', - '高清', - '流畅', - ][index]; + '杜比', + '4K', + '原画', + '蓝光', + '超清', + '高清', + '流畅', + ][index]; } diff --git a/lib/models/common/video/subtitle_pref_type.dart b/lib/models/common/video/subtitle_pref_type.dart index 5839c73ef..8be5aebd1 100644 --- a/lib/models/common/video/subtitle_pref_type.dart +++ b/lib/models/common/video/subtitle_pref_type.dart @@ -2,11 +2,11 @@ enum SubtitlePrefType { off, on, withoutAi, auto } extension SubtitlePrefTypeExt on SubtitlePrefType { String get description => const [ - '默认不显示字幕', - '优先选择非自动生成(ai)字幕', - '跳过自动生成(ai)字幕,选择第一个可用字幕', - '静音时等同第二项,非静音时等同第三项' - ][index]; + '默认不显示字幕', + '优先选择非自动生成(ai)字幕', + '跳过自动生成(ai)字幕,选择第一个可用字幕', + '静音时等同第二项,非静音时等同第三项', + ][index]; static const List _codeList = ['off', 'on', 'withoutAi', 'auto']; String get code => _codeList[index]; diff --git a/lib/models/dynamics/article_content_model.dart b/lib/models/dynamics/article_content_model.dart index ce6ad0eff..9410f5354 100644 --- a/lib/models/dynamics/article_content_model.dart +++ b/lib/models/dynamics/article_content_model.dart @@ -19,8 +19,9 @@ class ArticleContentModel { format = json['format'] == null ? null : Format.fromJson(json['format']); line = json['line'] == null ? null : Line.fromJson(json['line']); pic = json['pic'] == null ? null : Pic.fromJson(json['pic']); - linkCard = - json['link_card'] == null ? null : LinkCard.fromJson(json['link_card']); + linkCard = json['link_card'] == null + ? null + : LinkCard.fromJson(json['link_card']); code = json['code'] == null ? null : Code.fromJson(json['code']); list = json['list'] == null ? null : L1st.fromJson(json['list']); } @@ -79,8 +80,9 @@ class Text { List? nodes; Text.fromJson(Map json) { - nodes = - (json['nodes'] as List?)?.map((item) => Node.fromJson(item)).toList(); + nodes = (json['nodes'] as List?) + ?.map((item) => Node.fromJson(item)) + .toList(); } } @@ -95,8 +97,9 @@ class Node { nodeType = json['node_type']; word = json['word'] == null ? null : Word.fromJson(json['word']); rich = json['rich'] == null ? null : Rich.fromJson(json['rich']); - formula = - json['formula'] == null ? null : Formula.fromJson(json['formula']); + formula = json['formula'] == null + ? null + : Formula.fromJson(json['formula']); type = json['type']; } } @@ -122,8 +125,10 @@ class Word { style = json['style'] == null ? null : Style.fromJson(json['style']); color = json['color'] == null ? null - : int.tryParse('FF${(json['color'] as String).substring(1)}', - radix: 16); + : int.tryParse( + 'FF${(json['color'] as String).substring(1)}', + radix: 16, + ); fontLevel = json['font_level']; } } @@ -203,8 +208,9 @@ class Card { oid = json['oid']; type = json['type']; ugc = json['ugc'] == null ? null : Ugc.fromJson(json['ugc']); - itemNull = - json['item_null'] == null ? null : ItemNull.fromJson(json['item_null']); + itemNull = json['item_null'] == null + ? null + : ItemNull.fromJson(json['item_null']); common = json['common'] == null ? null : Common.fromJson(json['common']); live = json['live'] == null ? null : Live.fromJson(json['live']); opus = json['opus'] == null ? null : Opus.fromJson(json['opus']); diff --git a/lib/models/dynamics/result.dart b/lib/models/dynamics/result.dart index bf301ff6c..8d3249c3d 100644 --- a/lib/models/dynamics/result.dart +++ b/lib/models/dynamics/result.dart @@ -13,8 +13,10 @@ class DynamicsDataModel { String? offset; int? total; - static RegExp banWordForDyn = - RegExp(Pref.banWordForDyn, caseSensitive: false); + static RegExp banWordForDyn = RegExp( + Pref.banWordForDyn, + caseSensitive: false, + ); static bool enableFilter = banWordForDyn.pattern.isNotEmpty; static bool antiGoodsDyn = Pref.antiGoodsDyn; @@ -41,12 +43,14 @@ class DynamicsDataModel { continue; } if (enableFilter && - banWordForDyn.hasMatch((item.orig?.modules.moduleDynamic?.major - ?.opus?.summary?.text ?? - '') + - (item.modules.moduleDynamic?.major?.opus?.summary?.text ?? '') + - (item.orig?.modules.moduleDynamic?.desc?.text ?? '') + - (item.modules.moduleDynamic?.desc?.text ?? ''))) { + banWordForDyn.hasMatch( + (item.orig?.modules.moduleDynamic?.major?.opus?.summary?.text ?? + '') + + (item.modules.moduleDynamic?.major?.opus?.summary?.text ?? + '') + + (item.orig?.modules.moduleDynamic?.desc?.text ?? '') + + (item.modules.moduleDynamic?.desc?.text ?? ''), + )) { continue; } if (filterBan && @@ -97,7 +101,8 @@ class DynamicItemModel { modules = json['item']?['modules'] == null ? ItemModulesModel() : ItemModulesModel.fromOpusJson( - (json['item']['modules'] as List).cast()); + (json['item']['modules'] as List).cast(), + ); if (json['fallback'] != null) { fallback = Fallback.fromJson(json['fallback']); @@ -115,9 +120,9 @@ class Fallback { }); factory Fallback.fromJson(Map json) => Fallback( - id: json['id'], - type: json['type'], - ); + id: json['id'], + type: json['type'], + ); } // 单个动态详情 @@ -238,8 +243,9 @@ class ModuleTopDisplay { int? type; ModuleTopDisplay.fromJson(Map json) { - album = - json['album'] == null ? null : ModuleTopAlbum.fromJson(json['album']); + album = json['album'] == null + ? null + : ModuleTopAlbum.fromJson(json['album']); type = json['type']; } } @@ -353,8 +359,9 @@ class ModuleAuthorModel extends Avatar { pubTs = json['pub_ts'] == 0 ? null : json['pub_ts']; type = json['type']; if (PendantAvatar.showDynDecorate) { - decorate = - json['decorate'] == null ? null : Decorate.fromJson(json['decorate']); + decorate = json['decorate'] == null + ? null + : Decorate.fromJson(json['decorate']); } else { pendant = null; } @@ -379,13 +386,13 @@ class Decorate { }); factory Decorate.fromJson(Map json) => Decorate( - cardUrl: json["card_url"], - fan: json["fan"] == null ? null : Fan.fromJson(json["fan"]), - id: json["id"], - jumpUrl: json["jump_url"], - name: json["name"], - type: json["type"], - ); + cardUrl: json["card_url"], + fan: json["fan"] == null ? null : Fan.fromJson(json["fan"]), + id: json["id"], + jumpUrl: json["jump_url"], + name: json["name"], + type: json["type"], + ); } class Fan { @@ -404,12 +411,12 @@ class Fan { }); factory Fan.fromJson(Map json) => Fan( - color: json["color"], - isFan: json["is_fan"], - numPrefix: json["num_prefix"], - numStr: json["num_str"], - number: json["number"], - ); + color: json["color"], + isFan: json["is_fan"], + numPrefix: json["num_prefix"], + numStr: json["num_str"], + number: json["number"], + ); } // 单个动态详情 - 动态信息 @@ -430,8 +437,9 @@ class ModuleDynamicModel { additional = json['additional'] != null ? DynamicAddModel.fromJson(json['additional']) : null; - desc = - json['desc'] != null ? DynamicDescModel.fromJson(json['desc']) : null; + desc = json['desc'] != null + ? DynamicDescModel.fromJson(json['desc']) + : null; if (json['major'] != null) { major = DynamicMajorModel.fromJson(json['major']); } @@ -473,8 +481,9 @@ class DynamicAddModel { type = json['type']; vote = json['vote'] != null ? Vote.fromJson(json['vote']) : null; ugc = json['ugc'] != null ? Ugc.fromJson(json['ugc']) : null; - reserve = - json['reserve'] != null ? Reserve.fromJson(json['reserve']) : null; + reserve = json['reserve'] != null + ? Reserve.fromJson(json['reserve']) + : null; goods = json['goods'] != null ? Good.fromJson(json['goods']) : null; upowerLottery = json['upower_lottery'] != null ? UpowerLottery.fromJson(json['upower_lottery']) @@ -500,14 +509,14 @@ class AddMatch { }); factory AddMatch.fromJson(Map json) => AddMatch( - button: json["button"] == null ? null : Button.fromJson(json["button"]), - headText: json["head_text"], - idStr: json["id_str"], - jumpUrl: json["jump_url"], - matchInfo: json["match_info"] == null - ? null - : MatchInfo.fromJson(json["match_info"]), - ); + button: json["button"] == null ? null : Button.fromJson(json["button"]), + headText: json["head_text"], + idStr: json["id_str"], + jumpUrl: json["jump_url"], + matchInfo: json["match_info"] == null + ? null + : MatchInfo.fromJson(json["match_info"]), + ); } class MatchInfo { @@ -530,18 +539,18 @@ class MatchInfo { }); factory MatchInfo.fromJson(Map json) => MatchInfo( - centerBottom: json["center_bottom"], - centerTop: json["center_top"], - leftTeam: json["left_team"] == null - ? null - : TTeam.fromJson(json["left_team"]), - rightTeam: json["right_team"] == null - ? null - : TTeam.fromJson(json["right_team"]), - status: json["status"], - subTitle: json["sub_title"], - title: json["title"], - ); + centerBottom: json["center_bottom"], + centerTop: json["center_top"], + leftTeam: json["left_team"] == null + ? null + : TTeam.fromJson(json["left_team"]), + rightTeam: json["right_team"] == null + ? null + : TTeam.fromJson(json["right_team"]), + status: json["status"], + subTitle: json["sub_title"], + title: json["title"], + ); } class TTeam { @@ -556,10 +565,10 @@ class TTeam { }); factory TTeam.fromJson(Map json) => TTeam( - id: json["id"], - name: json["name"], - pic: json["pic"], - ); + id: json["id"], + name: json["name"], + pic: json["pic"], + ); } class AddCommon { @@ -588,17 +597,17 @@ class AddCommon { }); factory AddCommon.fromJson(Map json) => AddCommon( - button: json["button"] == null ? null : Button.fromJson(json["button"]), - cover: json["cover"], - desc1: json["desc1"], - desc2: json["desc2"], - headText: json["head_text"], - idStr: json["id_str"], - jumpUrl: json["jump_url"], - style: json["style"], - subType: json["sub_type"], - title: json["title"], - ); + button: json["button"] == null ? null : Button.fromJson(json["button"]), + cover: json["cover"], + desc1: json["desc1"], + desc2: json["desc2"], + headText: json["head_text"], + idStr: json["id_str"], + jumpUrl: json["jump_url"], + style: json["style"], + subType: json["sub_type"], + title: json["title"], + ); } class UpowerLottery { @@ -627,17 +636,17 @@ class UpowerLottery { }); factory UpowerLottery.fromJson(Map json) => UpowerLottery( - button: json["button"] == null ? null : Button.fromJson(json["button"]), - desc: json["desc"] == null ? null : Desc.fromJson(json["desc"]), - hint: json["hint"] == null ? null : Hint.fromJson(json["hint"]), - jumpUrl: json["jump_url"], - rid: json["rid"], - state: json["state"], - title: json["title"], - upMid: json["up_mid"], - upowerActionState: json["upower_action_state"], - upowerLevel: json["upower_level"], - ); + button: json["button"] == null ? null : Button.fromJson(json["button"]), + desc: json["desc"] == null ? null : Desc.fromJson(json["desc"]), + hint: json["hint"] == null ? null : Hint.fromJson(json["hint"]), + jumpUrl: json["jump_url"], + rid: json["rid"], + state: json["state"], + title: json["title"], + upMid: json["up_mid"], + upowerActionState: json["upower_action_state"], + upowerLevel: json["upower_level"], + ); } class Hint { @@ -650,9 +659,9 @@ class Hint { }); factory Hint.fromJson(Map json) => Hint( - style: json["style"], - text: json["text"], - ); + style: json["style"], + text: json["text"], + ); } class JumpStyle { @@ -665,9 +674,9 @@ class JumpStyle { }); factory JumpStyle.fromJson(Map json) => JumpStyle( - iconUrl: json["icon_url"], - text: json["text"], - ); + iconUrl: json["icon_url"], + text: json["text"], + ); } class Vote { @@ -771,8 +780,9 @@ class Reserve { int? upMid; Reserve.fromJson(Map json) { - button = - json['button'] == null ? null : ReserveBtn.fromJson(json['button']); + button = json['button'] == null + ? null + : ReserveBtn.fromJson(json['button']); desc1 = json['desc1'] == null ? null : Desc.fromJson(json['desc1']); desc2 = json['desc2'] == null ? null : Desc.fromJson(json['desc2']); desc3 = json['desc3'] == null ? null : Desc.fromJson(json['desc3']); @@ -948,22 +958,27 @@ class DynamicMajorModel { archive = json['archive'] != null ? DynamicArchiveModel.fromJson(json['archive']) : null; - draw = - json['draw'] != null ? DynamicDrawModel.fromJson(json['draw']) : null; + draw = json['draw'] != null + ? DynamicDrawModel.fromJson(json['draw']) + : null; ugcSeason = json['ugc_season'] != null ? DynamicArchiveModel.fromJson(json['ugc_season']) : null; - opus = - json['opus'] != null ? DynamicOpusModel.fromJson(json['opus']) : null; - pgc = - json['pgc'] != null ? DynamicArchiveModel.fromJson(json['pgc']) : null; + opus = json['opus'] != null + ? DynamicOpusModel.fromJson(json['opus']) + : null; + pgc = json['pgc'] != null + ? DynamicArchiveModel.fromJson(json['pgc']) + : null; liveRcmd = json['live_rcmd'] != null ? DynamicLiveModel.fromJson(json['live_rcmd']) : null; - live = - json['live'] != null ? DynamicLive2Model.fromJson(json['live']) : null; - none = - json['none'] != null ? DynamicNoneModel.fromJson(json['none']) : null; + live = json['live'] != null + ? DynamicLive2Model.fromJson(json['live']) + : null; + none = json['none'] != null + ? DynamicNoneModel.fromJson(json['none']) + : null; type = json['type']; courses = json['courses']; common = json['common'] == null ? null : Common.fromJson(json['common']); @@ -1026,11 +1041,11 @@ class LiveRcmd { }); factory LiveRcmd.fromJson(Map json) => LiveRcmd( - content: json["content"] == null - ? null - : LiveRcmdContent.fromJson(jsonDecode(json["content"])), - reserveType: json["reserve_type"], - ); + content: json["content"] == null + ? null + : LiveRcmdContent.fromJson(jsonDecode(json["content"])), + reserveType: json["reserve_type"], + ); } class LiveRcmdContent { @@ -1091,26 +1106,26 @@ class LivePlayInfo { }); factory LivePlayInfo.fromJson(Map json) => LivePlayInfo( - roomId: json["room_id"], - uid: json["uid"], - liveStatus: json["live_status"], - roomType: json["room_type"], - playType: json["play_type"], - title: json["title"], - cover: json["cover"], - online: json["online"], - areaId: json["area_id"], - areaName: json["area_name"], - parentAreaId: json["parent_area_id"], - parentAreaName: json["parent_area_name"], - liveScreenType: json["live_screen_type"], - liveStartTime: json["live_start_time"], - link: json["link"], - watchedShow: json["watched_show"] == null - ? null - : WatchedShow.fromJson(json["watched_show"]), - roomPaidType: json["room_paid_type"], - ); + roomId: json["room_id"], + uid: json["uid"], + liveStatus: json["live_status"], + roomType: json["room_type"], + playType: json["play_type"], + title: json["title"], + cover: json["cover"], + online: json["online"], + areaId: json["area_id"], + areaName: json["area_name"], + parentAreaId: json["parent_area_id"], + parentAreaName: json["parent_area_name"], + liveScreenType: json["live_screen_type"], + liveStartTime: json["live_start_time"], + link: json["link"], + watchedShow: json["watched_show"] == null + ? null + : WatchedShow.fromJson(json["watched_show"]), + roomPaidType: json["room_paid_type"], + ); } class DynamicTopicModel { @@ -1224,8 +1239,9 @@ class DynamicOpusModel { pics = (json['pics'] as List?) ?.map((e) => OpusPicModel.fromJson(e)) .toList(); - summary = - json['summary'] != null ? SummaryModel.fromJson(json['summary']) : null; + summary = json['summary'] != null + ? SummaryModel.fromJson(json['summary']) + : null; title = json['title']; } } @@ -1273,8 +1289,8 @@ class RichTextNodeItem { pics = json['pics'] == null ? null : (json['pics'] as List?) - ?.map((e) => OpusPicModel.fromJson(e)) - .toList(); + ?.map((e) => OpusPicModel.fromJson(e)) + .toList(); jumpUrl = json['jump_url']; } } @@ -1462,10 +1478,12 @@ class ModuleStatModel { // DynamicStat? coin; ModuleStatModel.fromJson(Map json) { - comment = - json['comment'] == null ? null : DynamicStat.fromJson(json['comment']); - forward = - json['forward'] == null ? null : DynamicStat.fromJson(json['forward']); + comment = json['comment'] == null + ? null + : DynamicStat.fromJson(json['comment']); + forward = json['forward'] == null + ? null + : DynamicStat.fromJson(json['forward']); like = json['like'] == null ? null : DynamicStat.fromJson(json['like']); if (json['favorite'] != null) { favorite = DynamicStat.fromJson(json['favorite']); @@ -1492,11 +1510,11 @@ class DynamicStat { } static int? _parseInt(dynamic x) => switch (x) { - int() => x, - String() => int.tryParse(x), - double() => x.toInt(), - _ => null - }; + int() => x, + String() => int.tryParse(x), + double() => x.toInt(), + _ => null, + }; } class Stat { diff --git a/lib/models/dynamics/vote_model.dart b/lib/models/dynamics/vote_model.dart index b2f466765..fbff1fbaa 100644 --- a/lib/models/dynamics/vote_model.dart +++ b/lib/models/dynamics/vote_model.dart @@ -76,7 +76,7 @@ class VoteInfo extends SimpleVoteInfo { myVotes = (json['my_votes'] as List?)?.cast(); // doVote options = (json['options'] as List?)?.map((v) => Option.fromJson(v)).toList() ?? -