refactor: Use the PachliError type for ApiError (#739)
In the previous code `PachliError` could correctly chain errors and generate error messages, `ApiError` didn't, which is why there was the temporary `ApiError.fmt()` extension function. Rewrite `ApiError` to implement `PachliError` so it gets these benefits and to reduce the number of different error-handling mechanisms in the code. Main changes: - `PachliError` is now an interface so it can be extended by other error interfaces. - All the `ApiError` subclasses implement `PachliError`, and can specify the error string and interpolated variables at the point of declaration. - Update `ListsRepository` and `ServerRepository` to return `PachliError` subclasses.
This commit is contained in:
parent
7bf8c382e1
commit
efd1c8e556
|
@ -124,7 +124,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="133"
|
line="132"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-sl/strings.xml"
|
file="src/main/res/values-sl/strings.xml"
|
||||||
line="180"
|
line="179"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="194"
|
line="193"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-bn-rIN/strings.xml"
|
file="src/main/res/values-bn-rIN/strings.xml"
|
||||||
line="201"
|
line="200"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-sl/strings.xml"
|
file="src/main/res/values-sl/strings.xml"
|
||||||
line="214"
|
line="213"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="236"
|
line="235"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -234,7 +234,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="237"
|
line="236"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-bn-rIN/strings.xml"
|
file="src/main/res/values-bn-rIN/strings.xml"
|
||||||
line="242"
|
line="241"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-hi/strings.xml"
|
file="src/main/res/values-hi/strings.xml"
|
||||||
line="270"
|
line="269"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="273"
|
line="272"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -289,21 +289,21 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
|
line="276"
|
||||||
|
column="5"/>
|
||||||
|
</issue>
|
||||||
|
|
||||||
|
<issue
|
||||||
|
id="MissingQuantity"
|
||||||
|
message="For locale "cs" (Czech) the following quantity should also be defined: `many` (e.g. "10.0 dne")"
|
||||||
|
errorLine1=" <plurals name="favs">"
|
||||||
|
errorLine2=" ^">
|
||||||
|
<location
|
||||||
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="277"
|
line="277"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
<issue
|
|
||||||
id="MissingQuantity"
|
|
||||||
message="For locale "cs" (Czech) the following quantity should also be defined: `many` (e.g. "10.0 dne")"
|
|
||||||
errorLine1=" <plurals name="favs">"
|
|
||||||
errorLine2=" ^">
|
|
||||||
<location
|
|
||||||
file="src/main/res/values-cs/strings.xml"
|
|
||||||
line="278"
|
|
||||||
column="5"/>
|
|
||||||
</issue>
|
|
||||||
|
|
||||||
<issue
|
<issue
|
||||||
id="MissingQuantity"
|
id="MissingQuantity"
|
||||||
message="For locale "cs" (Czech) the following quantity should also be defined: `many` (e.g. "10.0 dne")"
|
message="For locale "cs" (Czech) the following quantity should also be defined: `many` (e.g. "10.0 dne")"
|
||||||
|
@ -311,7 +311,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="283"
|
line="282"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="302"
|
line="301"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="313"
|
line="312"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="327"
|
line="326"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="332"
|
line="331"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="337"
|
line="336"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-bg/strings.xml"
|
file="src/main/res/values-bg/strings.xml"
|
||||||
line="369"
|
line="368"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -388,7 +388,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="369"
|
line="368"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -399,7 +399,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="397"
|
line="396"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -410,7 +410,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="401"
|
line="400"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="405"
|
line="404"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="409"
|
line="408"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -443,7 +443,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="417"
|
line="416"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -454,7 +454,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="422"
|
line="421"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -465,7 +465,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-ca/strings.xml"
|
file="src/main/res/values-ca/strings.xml"
|
||||||
line="425"
|
line="424"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -476,7 +476,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-cs/strings.xml"
|
file="src/main/res/values-cs/strings.xml"
|
||||||
line="427"
|
line="426"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -509,7 +509,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="34"
|
line="33"
|
||||||
column="44"/>
|
column="44"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -520,7 +520,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-tr/strings.xml"
|
file="src/main/res/values-tr/strings.xml"
|
||||||
line="40"
|
line="39"
|
||||||
column="50"/>
|
column="50"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -531,7 +531,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-tr/strings.xml"
|
file="src/main/res/values-tr/strings.xml"
|
||||||
line="40"
|
line="39"
|
||||||
column="46"/>
|
column="46"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="71"
|
line="70"
|
||||||
column="38"/>
|
column="38"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -553,7 +553,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="73"
|
line="72"
|
||||||
column="46"/>
|
column="46"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -564,7 +564,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="79"
|
line="78"
|
||||||
column="44"/>
|
column="44"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -575,7 +575,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="102"
|
line="101"
|
||||||
column="45"/>
|
column="45"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -586,7 +586,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="106"
|
line="105"
|
||||||
column="44"/>
|
column="44"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -597,7 +597,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="107"
|
line="106"
|
||||||
column="49"/>
|
column="49"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -608,7 +608,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="110"
|
line="109"
|
||||||
column="38"/>
|
column="38"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -619,7 +619,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="125"
|
line="124"
|
||||||
column="70"/>
|
column="70"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="158"
|
line="157"
|
||||||
column="78"/>
|
column="78"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -641,7 +641,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="164"
|
line="163"
|
||||||
column="65"/>
|
column="65"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -652,7 +652,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="200"
|
line="199"
|
||||||
column="32"/>
|
column="32"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -663,7 +663,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="268"
|
line="267"
|
||||||
column="43"/>
|
column="43"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -674,7 +674,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="396"
|
line="395"
|
||||||
column="86"/>
|
column="86"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -685,7 +685,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-tr/strings.xml"
|
file="src/main/res/values-tr/strings.xml"
|
||||||
line="504"
|
line="503"
|
||||||
column="294"/>
|
column="294"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -696,7 +696,7 @@
|
||||||
errorLine2=" ^">
|
errorLine2=" ^">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values-nb-rNO/strings.xml"
|
file="src/main/res/values-nb-rNO/strings.xml"
|
||||||
line="526"
|
line="525"
|
||||||
column="51"/>
|
column="51"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -729,7 +729,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="101"
|
line="100"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -740,7 +740,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="288"
|
line="287"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -751,7 +751,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="339"
|
line="338"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -762,7 +762,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="458"
|
line="457"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -773,7 +773,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="633"
|
line="632"
|
||||||
column="5"/>
|
column="5"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1290,7 +1290,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="76"
|
line="75"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1301,7 +1301,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="82"
|
line="81"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1312,7 +1312,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="103"
|
line="102"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1323,7 +1323,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="111"
|
line="110"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1334,7 +1334,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="145"
|
line="144"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1345,7 +1345,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="204"
|
line="203"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1356,7 +1356,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="225"
|
line="224"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1367,7 +1367,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="226"
|
line="225"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1378,7 +1378,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="249"
|
line="248"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1389,7 +1389,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="278"
|
line="277"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1400,7 +1400,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="349"
|
line="348"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1411,7 +1411,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="389"
|
line="388"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1422,7 +1422,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="425"
|
line="424"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1433,7 +1433,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="428"
|
line="427"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1444,7 +1444,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="429"
|
line="428"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1455,7 +1455,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="430"
|
line="429"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1466,7 +1466,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="431"
|
line="430"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1477,7 +1477,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="432"
|
line="431"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1488,7 +1488,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="444"
|
line="443"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1499,7 +1499,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="445"
|
line="444"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1510,7 +1510,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="496"
|
line="495"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1521,7 +1521,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="497"
|
line="496"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1532,7 +1532,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="508"
|
line="507"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1543,7 +1543,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="509"
|
line="508"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1554,7 +1554,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="510"
|
line="509"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1565,7 +1565,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="512"
|
line="511"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1576,7 +1576,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="550"
|
line="549"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1587,7 +1587,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="591"
|
line="590"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1598,7 +1598,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="597"
|
line="596"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1609,7 +1609,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="625"
|
line="624"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1620,7 +1620,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="639"
|
line="638"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
@ -1631,7 +1631,7 @@
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/res/values/strings.xml"
|
file="src/main/res/values/strings.xml"
|
||||||
line="652"
|
line="651"
|
||||||
column="13"/>
|
column="13"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,6 @@ import java.util.regex.Pattern
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
||||||
|
@ -332,7 +331,6 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
||||||
selectListBinding.progressBar.hide()
|
selectListBinding.progressBar.hide()
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
Snackbar.make(binding.root, R.string.error_list_load, Snackbar.LENGTH_LONG).show()
|
Snackbar.make(binding.root, R.string.error_list_load, Snackbar.LENGTH_LONG).show()
|
||||||
Timber.w(it.throwable, "failed to load lists")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,7 @@ abstract class SFragment<T : IStatusViewData> : Fragment(), StatusActionListener
|
||||||
val msg = getString(
|
val msg = getString(
|
||||||
R.string.server_repository_error,
|
R.string.server_repository_error,
|
||||||
accountManager.activeAccount!!.domain,
|
accountManager.activeAccount!!.domain,
|
||||||
it.msg(requireContext()),
|
it.fmt(requireContext()),
|
||||||
)
|
)
|
||||||
Timber.e(msg)
|
Timber.e(msg)
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -19,36 +19,41 @@ package app.pachli.core.common
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import app.pachli.core.common.string.unicodeWrap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for errors throughout the app.
|
* Interface for errors throughout the app.
|
||||||
*
|
*
|
||||||
* Derive new error class hierarchies for different components using a sealed
|
* Derive new error class hierarchies for different components using a sealed
|
||||||
* class hierarchy like so:
|
* class hierarchy like so:
|
||||||
*
|
*
|
||||||
* ```kotlin
|
* ```kotlin
|
||||||
* sealed class Error(
|
* sealed class Error(
|
||||||
* @StringRes resourceId: Int,
|
* @StringRes override val resourceId: Int,
|
||||||
* vararg formatArgs: String,
|
* override val formatArgs: Array<out String>,
|
||||||
* source: PachliError? = null,
|
* cause: PachliError? = null,
|
||||||
* ) : PachliError(resourceId, *formatArgs, source = source) {
|
* ) : PachliError {
|
||||||
* data object SomeProblem : Error(R.string.error_some_problem)
|
* data object SomeProblem : Error(R.string.error_some_problem)
|
||||||
* data class OutOfRange(val input: Int) : Error(
|
* data class OutOfRange(val input: Int) : Error(
|
||||||
* R.string.error_out_of_range
|
* R.string.error_out_of_range, // "Value %1$d is out of range"
|
||||||
* input,
|
* input,
|
||||||
* )
|
* )
|
||||||
* data class Fetch(val url: String, val e: PachliError) : Error(
|
* data class Fetch(val url: String, val cause: PachliError) : Error(
|
||||||
* R.string.error_fetch,
|
* R.string.error_fetch, // "Could not fetch %1$s: %2$s"
|
||||||
* url,
|
* url,
|
||||||
* source = e,
|
* cause = cause,
|
||||||
* )
|
* )
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* In this example `SomeProblem` represents an error with no additional context,
|
* In this example `SomeProblem` represents an error with no additional context.
|
||||||
* `OtherProblem` is an error relating to a URL and the URL will be included in
|
*
|
||||||
* the error message, and `WrappedError` represents an error that wraps another
|
* `OutOfRange` is an error relating to a single value with no underlying cause.
|
||||||
* error that was the actual cause.
|
* The value (`input`) will be inserted in the string at `%1$s`.
|
||||||
|
*
|
||||||
|
* `Fetch` is an error relating to a URL with an underlying cause. The URL will be
|
||||||
|
* included in the error message at `%1$s`, and the string representation of the
|
||||||
|
* cause will be included at `%2$s`.
|
||||||
*
|
*
|
||||||
* Possible string resources for those errors would be:
|
* Possible string resources for those errors would be:
|
||||||
*
|
*
|
||||||
|
@ -57,23 +62,27 @@ import androidx.annotation.StringRes
|
||||||
* <string name="error_out_of_range">Value %1$d is out of range</string>
|
* <string name="error_out_of_range">Value %1$d is out of range</string>
|
||||||
* <string name="error_fetch">Could not fetch %1$s: %2$s</string>
|
* <string name="error_fetch">Could not fetch %1$s: %2$s</string>
|
||||||
* ```
|
* ```
|
||||||
*
|
|
||||||
* In that last example the `url` parameter will be interpolated as the first
|
|
||||||
* placeholder and the error message from the error passed as the `source`
|
|
||||||
* parameter will be interpolated as the second placeholder.
|
|
||||||
*
|
|
||||||
* @property resourceId String resource ID for the error message
|
|
||||||
* @property formatArgs 0 or more arguments to interpolate in to the string resource
|
|
||||||
* @property source (optional) The underlying error that caused this error
|
|
||||||
*/
|
*/
|
||||||
open class PachliError(
|
interface PachliError {
|
||||||
@StringRes private val resourceId: Int,
|
/** String resource ID for the error message. */
|
||||||
private vararg val formatArgs: String,
|
@get:StringRes
|
||||||
val source: PachliError? = null,
|
val resourceId: Int
|
||||||
) {
|
|
||||||
fun msg(context: Context): String {
|
/** Arguments to be interpolated in to the string from [resourceId]. */
|
||||||
|
val formatArgs: Array<out String>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cause of this error. If present the string representation of `cause`
|
||||||
|
* will be set as the last format argument when formatting [resourceId].
|
||||||
|
*/
|
||||||
|
val cause: PachliError?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A localised, unicode-wrapped error message for this error.
|
||||||
|
*/
|
||||||
|
fun fmt(context: Context): String {
|
||||||
val args = mutableListOf(*formatArgs)
|
val args = mutableListOf(*formatArgs)
|
||||||
source?.let { args.add(it.msg(context)) }
|
cause?.let { args.add(it.fmt(context)) }
|
||||||
return context.getString(resourceId, *args.toTypedArray())
|
return context.getString(resourceId, *args.toTypedArray()).unicodeWrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package app.pachli.core.data.repository
|
package app.pachli.core.data.repository
|
||||||
|
|
||||||
|
import app.pachli.core.common.PachliError
|
||||||
import app.pachli.core.network.model.MastoList
|
import app.pachli.core.network.model.MastoList
|
||||||
import app.pachli.core.network.model.TimelineAccount
|
import app.pachli.core.network.model.TimelineAccount
|
||||||
import app.pachli.core.network.model.UserListRepliesPolicy
|
import app.pachli.core.network.model.UserListRepliesPolicy
|
||||||
|
@ -36,26 +37,26 @@ interface HasListId {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Errors that can be returned from this repository */
|
/** Errors that can be returned from this repository */
|
||||||
interface ListsError : ApiError {
|
interface ListsError : PachliError {
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Create(private val error: ApiError) : ListsError, ApiError by error
|
value class Create(private val error: ApiError) : ListsError, PachliError by error
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Retrieve(private val error: ApiError) : ListsError, ApiError by error
|
value class Retrieve(private val error: ApiError) : ListsError, PachliError by error
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Update(private val error: ApiError) : ListsError, ApiError by error
|
value class Update(private val error: ApiError) : ListsError, PachliError by error
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Delete(private val error: ApiError) : ListsError, ApiError by error
|
value class Delete(private val error: ApiError) : ListsError, PachliError by error
|
||||||
|
|
||||||
data class GetListsWithAccount(val accountId: String, private val error: ApiError) : ListsError, ApiError by error
|
data class GetListsWithAccount(val accountId: String, private val error: ApiError) : ListsError, PachliError by error
|
||||||
|
|
||||||
data class GetAccounts(override val listId: String, private val error: ApiError) : ListsError, HasListId, ApiError by error
|
data class GetAccounts(override val listId: String, private val error: ApiError) : ListsError, HasListId, PachliError by error
|
||||||
|
|
||||||
data class AddAccounts(override val listId: String, private val error: ApiError) : ListsError, HasListId, ApiError by error
|
data class AddAccounts(override val listId: String, private val error: ApiError) : ListsError, HasListId, PachliError by error
|
||||||
|
|
||||||
data class DeleteAccounts(override val listId: String, private val error: ApiError) : ListsError, HasListId, ApiError by error
|
data class DeleteAccounts(override val listId: String, private val error: ApiError) : ListsError, HasListId, PachliError by error
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ListsRepository {
|
interface ListsRepository {
|
||||||
|
|
|
@ -119,13 +119,14 @@ class ServerRepository @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Error(
|
sealed class Error(
|
||||||
@StringRes resourceId: Int,
|
@StringRes override val resourceId: Int,
|
||||||
vararg formatArgs: String,
|
override val formatArgs: Array<out String> = emptyArray<String>(),
|
||||||
source: PachliError? = null,
|
override val cause: PachliError? = null,
|
||||||
) : PachliError(resourceId, *formatArgs, source = source) {
|
) : PachliError {
|
||||||
|
|
||||||
data class GetWellKnownNodeInfo(val throwable: Throwable) : Error(
|
data class GetWellKnownNodeInfo(val throwable: Throwable) : Error(
|
||||||
R.string.server_repository_error_get_well_known_node_info,
|
R.string.server_repository_error_get_well_known_node_info,
|
||||||
throwable.localizedMessage,
|
throwable.localizedMessage?.let { arrayOf(it) }.orEmpty(),
|
||||||
)
|
)
|
||||||
|
|
||||||
data object UnsupportedSchema : Error(
|
data object UnsupportedSchema : Error(
|
||||||
|
@ -134,24 +135,23 @@ class ServerRepository @Inject constructor(
|
||||||
|
|
||||||
data class GetNodeInfo(val url: String, val throwable: Throwable) : Error(
|
data class GetNodeInfo(val url: String, val throwable: Throwable) : Error(
|
||||||
R.string.server_repository_error_get_node_info,
|
R.string.server_repository_error_get_node_info,
|
||||||
url,
|
arrayOf(url, throwable.localizedMessage ?: ""),
|
||||||
throwable.localizedMessage,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ValidateNodeInfo(val url: String, val error: NodeInfo.Error) : Error(
|
data class ValidateNodeInfo(val url: String, val error: NodeInfo.Error) : Error(
|
||||||
R.string.server_repository_error_validate_node_info,
|
R.string.server_repository_error_validate_node_info,
|
||||||
url,
|
arrayOf(url),
|
||||||
source = error,
|
cause = error,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class GetInstanceInfoV1(val throwable: Throwable) : Error(
|
data class GetInstanceInfoV1(val throwable: Throwable) : Error(
|
||||||
R.string.server_repository_error_get_instance_info,
|
R.string.server_repository_error_get_instance_info,
|
||||||
throwable.localizedMessage,
|
throwable.localizedMessage?.let { arrayOf(it) }.orEmpty(),
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Capabilities(val error: Server.Error) : Error(
|
data class Capabilities(val error: Server.Error) : Error(
|
||||||
R.string.server_repository_error_capabilities,
|
R.string.server_repository_error_capabilities,
|
||||||
source = error,
|
cause = error,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<issues format="6" by="lint 8.3.0" type="baseline" client="gradle" dependencies="false" name="AGP (8.3.0)" variant="all" version="8.3.0">
|
<issues format="6" by="lint 8.3.2" type="baseline" client="gradle" dependencies="false" name="AGP (8.3.2)" variant="all" version="8.3.2">
|
||||||
|
|
||||||
</issues>
|
</issues>
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package app.pachli.core.network
|
package app.pachli.core.network
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.annotation.VisibleForTesting.Companion.PRIVATE
|
import androidx.annotation.VisibleForTesting.Companion.PRIVATE
|
||||||
import app.pachli.core.common.PachliError
|
import app.pachli.core.common.PachliError
|
||||||
|
@ -296,16 +295,13 @@ data class Server(
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Errors that can occur when processing server capabilities */
|
/** Errors that can occur when processing server capabilities */
|
||||||
sealed class Error(
|
sealed interface Error : PachliError {
|
||||||
@StringRes resourceId: Int,
|
|
||||||
vararg formatArgs: String,
|
|
||||||
) : PachliError(resourceId, *formatArgs) {
|
|
||||||
/** Could not parse the server's version string */
|
/** Could not parse the server's version string */
|
||||||
data class UnparseableVersion(val version: String, val throwable: Throwable) : Error(
|
data class UnparseableVersion(val version: String, val throwable: Throwable) : Error {
|
||||||
R.string.server_error_unparseable_version,
|
override val resourceId = R.string.server_error_unparseable_version
|
||||||
version,
|
override val formatArgs: Array<String> = arrayOf(version, throwable.localizedMessage ?: "")
|
||||||
throwable.localizedMessage,
|
override val cause: PachliError? = null
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,10 +77,11 @@ data class NodeInfo(val software: Software) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Error(
|
sealed class Error(
|
||||||
@StringRes resourceId: Int,
|
@StringRes override val resourceId: Int,
|
||||||
vararg formatArgs: String,
|
) : PachliError {
|
||||||
source: PachliError? = null,
|
override val formatArgs = emptyArray<String>()
|
||||||
) : PachliError(resourceId, *formatArgs, source = source) {
|
override val cause: PachliError? = null
|
||||||
|
|
||||||
data object NoSoftwareBlock : Error(R.string.node_info_error_no_software)
|
data object NoSoftwareBlock : Error(R.string.node_info_error_no_software)
|
||||||
data object NoSoftwareName : Error(R.string.node_info_error_no_software_name)
|
data object NoSoftwareName : Error(R.string.node_info_error_no_software_name)
|
||||||
data object NoSoftwareVersion : Error(R.string.node_info_error_no_software_version)
|
data object NoSoftwareVersion : Error(R.string.node_info_error_no_software_version)
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
|
|
||||||
package app.pachli.core.network.retrofit.apiresult
|
package app.pachli.core.network.retrofit.apiresult
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import app.pachli.core.common.PachliError
|
||||||
|
import app.pachli.core.network.R
|
||||||
|
import app.pachli.core.network.extensions.getServerErrorMessage
|
||||||
import com.github.michaelbull.result.Err
|
import com.github.michaelbull.result.Err
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
import com.github.michaelbull.result.Result
|
import com.github.michaelbull.result.Result
|
||||||
|
@ -45,50 +49,57 @@ data class ApiResponse<out T>(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A failed response from an API call.
|
* A failed response from an API call.
|
||||||
|
*
|
||||||
|
* @param resourceId String resource ID of the error message.
|
||||||
|
* @param throwable The [Throwable] that caused this error. The server
|
||||||
|
* message (if it exists), or [Throwable.getLocalizedMessage] will be
|
||||||
|
* interpolated in to this string at `%1$s`.
|
||||||
*/
|
*/
|
||||||
interface ApiError {
|
sealed class ApiError(
|
||||||
// This has to be Throwable, not Exception, because Retrofit exposes
|
@StringRes override val resourceId: Int,
|
||||||
// errors as Throwable
|
val throwable: Throwable,
|
||||||
val throwable: Throwable
|
) : PachliError {
|
||||||
|
override val formatArgs = (
|
||||||
|
throwable.getServerErrorMessage() ?: throwable.localizedMessage
|
||||||
|
)?.let { arrayOf(it) }.orEmpty()
|
||||||
|
override val cause: PachliError? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun from(exception: Throwable): ApiError {
|
fun from(throwable: Throwable): ApiError {
|
||||||
return when (exception) {
|
return when (throwable) {
|
||||||
is HttpException -> when (exception.code()) {
|
is HttpException -> when (throwable.code()) {
|
||||||
in 400..499 -> ClientError.from(exception)
|
in 400..499 -> ClientError.from(throwable)
|
||||||
in 500..599 -> ServerError.from(exception)
|
in 500..599 -> ServerError.from(throwable)
|
||||||
else -> Unknown(exception)
|
else -> Unknown(throwable)
|
||||||
}
|
}
|
||||||
|
|
||||||
is JsonDataException -> JsonParse(exception)
|
is JsonDataException -> JsonParseError(throwable)
|
||||||
is IOException -> IO(exception)
|
is IOException -> IoError(throwable)
|
||||||
else -> Unknown(exception)
|
else -> Unknown(throwable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Unknown(override val throwable: Throwable) : ApiError
|
data class Unknown(val exception: Throwable) : ApiError(
|
||||||
|
R.string.error_generic_fmt,
|
||||||
|
exception,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface HttpError : ApiError {
|
sealed class HttpError(
|
||||||
override val throwable: HttpException
|
@StringRes override val resourceId: Int,
|
||||||
|
open val exception: HttpException,
|
||||||
/**
|
) : ApiError(resourceId, exception)
|
||||||
* The error message for this error, one of (in preference order):
|
|
||||||
*
|
|
||||||
* - The error body of the response that created this error
|
|
||||||
* - The throwable.message
|
|
||||||
* - Literal string "Unknown"
|
|
||||||
*/
|
|
||||||
val message
|
|
||||||
get() = throwable.response()?.errorBody()?.string() ?: throwable.message() ?: "Unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 4xx errors */
|
/** 4xx errors */
|
||||||
sealed interface ClientError : HttpError {
|
sealed class ClientError(
|
||||||
|
@StringRes override val resourceId: Int,
|
||||||
|
exception: HttpException,
|
||||||
|
) : HttpError(resourceId, exception) {
|
||||||
companion object {
|
companion object {
|
||||||
fun from(exception: HttpException): ClientError {
|
fun from(exception: HttpException): ClientError {
|
||||||
return when (exception.code()) {
|
return when (exception.code()) {
|
||||||
|
400 -> BadRequest(exception)
|
||||||
401 -> Unauthorized(exception)
|
401 -> Unauthorized(exception)
|
||||||
404 -> NotFound(exception)
|
404 -> NotFound(exception)
|
||||||
410 -> Gone(exception)
|
410 -> Gone(exception)
|
||||||
|
@ -97,14 +108,32 @@ sealed interface ClientError : HttpError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Unauthorized(override val throwable: HttpException) : ClientError
|
/** 400 Bad request */
|
||||||
data class NotFound(override val throwable: HttpException) : ClientError
|
data class BadRequest(override val exception: HttpException) :
|
||||||
data class Gone(override val throwable: HttpException) : ClientError
|
ClientError(R.string.error_generic_fmt, exception)
|
||||||
data class UnknownClientError(override val throwable: HttpException) : ClientError
|
|
||||||
|
/** 401 Unauthorized */
|
||||||
|
data class Unauthorized(override val exception: HttpException) :
|
||||||
|
ClientError(R.string.error_generic_fmt, exception)
|
||||||
|
|
||||||
|
/** 404 Not found */
|
||||||
|
data class NotFound(override val exception: HttpException) :
|
||||||
|
ClientError(R.string.error_404_not_found_fmt, exception)
|
||||||
|
|
||||||
|
/** 410 Gone */
|
||||||
|
data class Gone(override val exception: HttpException) :
|
||||||
|
ClientError(R.string.error_generic_fmt, exception)
|
||||||
|
|
||||||
|
/** All other 4xx client errors */
|
||||||
|
data class UnknownClientError(override val exception: HttpException) :
|
||||||
|
ClientError(R.string.error_generic_fmt, exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 5xx errors */
|
/** 5xx errors */
|
||||||
sealed interface ServerError : HttpError {
|
sealed class ServerError(
|
||||||
|
@StringRes override val resourceId: Int,
|
||||||
|
exception: HttpException,
|
||||||
|
) : HttpError(resourceId, exception) {
|
||||||
companion object {
|
companion object {
|
||||||
fun from(exception: HttpException): ServerError {
|
fun from(exception: HttpException): ServerError {
|
||||||
return when (exception.code()) {
|
return when (exception.code()) {
|
||||||
|
@ -117,15 +146,32 @@ sealed interface ServerError : HttpError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Internal(override val throwable: HttpException) : ServerError
|
/** 500 Internal error */
|
||||||
data class NotImplemented(override val throwable: HttpException) : ServerError
|
data class Internal(override val exception: HttpException) :
|
||||||
data class BadGateway(override val throwable: HttpException) : ServerError
|
ServerError(R.string.error_generic_fmt, exception)
|
||||||
data class ServiceUnavailable(override val throwable: HttpException) : ServerError
|
|
||||||
data class UnknownServerError(override val throwable: HttpException) : ServerError
|
/** 501 Not implemented */
|
||||||
|
data class NotImplemented(override val exception: HttpException) :
|
||||||
|
ServerError(R.string.error_404_not_found_fmt, exception)
|
||||||
|
|
||||||
|
/** 502 Bad gateway */
|
||||||
|
data class BadGateway(override val exception: HttpException) :
|
||||||
|
ServerError(R.string.error_generic_fmt, exception)
|
||||||
|
|
||||||
|
/** 503 Service unavailable */
|
||||||
|
data class ServiceUnavailable(override val exception: HttpException) :
|
||||||
|
ServerError(R.string.error_generic_fmt, exception)
|
||||||
|
|
||||||
|
/** All other 5xx server errors */
|
||||||
|
data class UnknownServerError(override val exception: HttpException) :
|
||||||
|
ServerError(R.string.error_generic_fmt, exception)
|
||||||
}
|
}
|
||||||
data class JsonParse(override val throwable: JsonDataException) : ApiError
|
|
||||||
sealed interface NetworkError : ApiError
|
data class JsonParseError(val exception: JsonDataException) :
|
||||||
data class IO(override val throwable: Exception) : NetworkError
|
ApiError(R.string.error_json_data_fmt, exception)
|
||||||
|
|
||||||
|
data class IoError(val exception: IOException) :
|
||||||
|
ApiError(R.string.error_network_fmt, exception)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an [ApiResult] from a [Response].
|
* Creates an [ApiResult] from a [Response].
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">وقع خطأ: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">خادمك لا يدعم هذه الميزة: %1$s</string>
|
||||||
|
<string name="error_network_fmt">وقع خطأ في الشبكة: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">Es ist ein Fehler aufgetreten: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Dein Server unterstützt diese Funktion nicht: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Ein Netzwerkfehler ist aufgetreten: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">An error occurred: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Your server does not support this feature: %1$s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -4,4 +4,8 @@
|
||||||
<string name="node_info_error_no_software_version">versión del programa faltante, vacía o en blanco</string>
|
<string name="node_info_error_no_software_version">versión del programa faltante, vacía o en blanco</string>
|
||||||
<string name="server_error_unparseable_version">no se pudo analizar \"%1$s\" como una versión: %2$s</string>
|
<string name="server_error_unparseable_version">no se pudo analizar \"%1$s\" como una versión: %2$s</string>
|
||||||
<string name="node_info_error_no_software">no hay bloque sobre el programa</string>
|
<string name="node_info_error_no_software">no hay bloque sobre el programa</string>
|
||||||
</resources>
|
<string name="error_generic_fmt">Ha ocurrido un error: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Su servidor no soporta esta función: %1$s</string>
|
||||||
|
<string name="error_json_data_fmt">Tu servidor devolvió una respuesta inválida: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Ha ocurrido un error de red: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">Tapahtui virhe: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Palvelimesi ei tue tätä ominaisuutta: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Tapahtui verkkovirhe: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">Une erreur s\'est produite : %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Votre serveur ne prend pas en charge cette fonctionnalité: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Une erreur réseau s\'est produite : %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">Terjadi error: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Server Anda tidak mendukung fitur ini: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Jaringan error: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">Si è verificato un errore: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Il tuo server non supporta questa feature: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Si è verificato un errore di rete: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">エラーが発生しました: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">あなたのサーバーはこの機能をサポートしていません: %1$s</string>
|
||||||
|
<string name="error_network_fmt">ネットワーク エラーが発生しました: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">Tella-d tuccḍa: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -4,4 +4,7 @@
|
||||||
<string name="node_info_error_no_software_name">software naam mist, is leeg of blanco</string>
|
<string name="node_info_error_no_software_name">software naam mist, is leeg of blanco</string>
|
||||||
<string name="node_info_error_no_software_version">software versie mist, is leeg of blanco</string>
|
<string name="node_info_error_no_software_version">software versie mist, is leeg of blanco</string>
|
||||||
<string name="server_error_unparseable_version">kon \"%1$s\" niet verwerken als een versie: %2$s</string>
|
<string name="server_error_unparseable_version">kon \"%1$s\" niet verwerken als een versie: %2$s</string>
|
||||||
</resources>
|
<string name="error_generic_fmt">Er deed zich een fout voor: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Je server beschikt niet over ondersteuning voor deze feature: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Er deed zich een netwerkfout voor: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources></resources>
|
<resources>
|
||||||
|
<string name="error_generic_fmt">Ocorreu um erro: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Tua instância não suporta este recurso: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Ocorreu um erro de rede: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -4,4 +4,7 @@
|
||||||
<string name="node_info_error_no_software">innehöll inget mjukvarublock</string>
|
<string name="node_info_error_no_software">innehöll inget mjukvarublock</string>
|
||||||
<string name="node_info_error_no_software_name">mjukvarunamnet saknas, är tomt eller blankt</string>
|
<string name="node_info_error_no_software_name">mjukvarunamnet saknas, är tomt eller blankt</string>
|
||||||
<string name="server_error_unparseable_version">Kunde inte analysera \"%1$s\" som en version: %2$s</string>
|
<string name="server_error_unparseable_version">Kunde inte analysera \"%1$s\" som en version: %2$s</string>
|
||||||
</resources>
|
<string name="error_generic_fmt">Ett fel har uppstått: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Din server stöder inte denna funktion: %1$s</string>
|
||||||
|
<string name="error_network_fmt">Ett nätverksfel har uppstått: %s</string>
|
||||||
|
</resources>
|
||||||
|
|
|
@ -21,4 +21,8 @@
|
||||||
<string name="node_info_error_no_software_version">software version is missing, empty, or blank</string>
|
<string name="node_info_error_no_software_version">software version is missing, empty, or blank</string>
|
||||||
|
|
||||||
<string name="server_error_unparseable_version">could not parse \"%1$s\" as a version: %2$s</string>
|
<string name="server_error_unparseable_version">could not parse \"%1$s\" as a version: %2$s</string>
|
||||||
|
<string name="error_generic_fmt">An error occurred: %s</string>
|
||||||
|
<string name="error_404_not_found_fmt">Your server does not support this feature: %1$s</string>
|
||||||
|
<string name="error_json_data_fmt">Your server returned an invalid response: %1$s</string>
|
||||||
|
<string name="error_network_fmt">A network error occurred: %s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -89,11 +89,10 @@ class ApiResultCallTest {
|
||||||
override fun onResponse(call: Call<ApiResult<String>>, response: Response<ApiResult<String>>) {
|
override fun onResponse(call: Call<ApiResult<String>>, response: Response<ApiResult<String>>) {
|
||||||
val error = response.body()?.getError() as? ClientError.NotFound
|
val error = response.body()?.getError() as? ClientError.NotFound
|
||||||
assertThat(error).isInstanceOf(ClientError.NotFound::class.java)
|
assertThat(error).isInstanceOf(ClientError.NotFound::class.java)
|
||||||
assertThat(error?.message).isEqualTo("not found")
|
|
||||||
|
|
||||||
val throwable = error?.throwable
|
val exception = error?.exception
|
||||||
assertThat(throwable).isInstanceOf(HttpException::class.java)
|
assertThat(exception).isInstanceOf(HttpException::class.java)
|
||||||
assertThat(throwable?.code()).isEqualTo(404)
|
assertThat(exception?.code()).isEqualTo(404)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<ApiResult<String>>, t: Throwable) {
|
override fun onFailure(call: Call<ApiResult<String>>, t: Throwable) {
|
||||||
|
@ -107,7 +106,7 @@ class ApiResultCallTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `should parse call with IOException as ApiResult-failure`() {
|
fun `should parse call with IOException as ApiResult-failure`() {
|
||||||
val error = Err(IO(IOException()))
|
val error = Err(IoError(IOException()))
|
||||||
|
|
||||||
networkApiResultCall.enqueue(
|
networkApiResultCall.enqueue(
|
||||||
object : Callback<ApiResult<String>> {
|
object : Callback<ApiResult<String>> {
|
||||||
|
|
|
@ -140,8 +140,8 @@ class ApiTest {
|
||||||
|
|
||||||
val error = responseObject as? ServerError.Internal
|
val error = responseObject as? ServerError.Internal
|
||||||
assertThat(error).isInstanceOf(ServerError.Internal::class.java)
|
assertThat(error).isInstanceOf(ServerError.Internal::class.java)
|
||||||
assertThat(error?.throwable?.code()).isEqualTo(500)
|
assertThat(error?.exception?.code()).isEqualTo(500)
|
||||||
assertThat(error?.throwable?.message()).isEqualTo("Server Error")
|
assertThat(error?.exception?.message()).isEqualTo("Server Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -155,8 +155,8 @@ class ApiTest {
|
||||||
|
|
||||||
val error = responseObject as? ServerError.Internal
|
val error = responseObject as? ServerError.Internal
|
||||||
assertThat(error).isInstanceOf(ServerError.Internal::class.java)
|
assertThat(error).isInstanceOf(ServerError.Internal::class.java)
|
||||||
assertThat(error?.throwable?.code()).isEqualTo(500)
|
assertThat(error?.exception?.code()).isEqualTo(500)
|
||||||
assertThat(error?.throwable?.message()).isEqualTo("Server Error")
|
assertThat(error?.exception?.message()).isEqualTo("Server Error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -167,9 +167,9 @@ class ApiTest {
|
||||||
api.getSiteAsync()
|
api.getSiteAsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
val error = responseObject.getError() as? IO
|
val error = responseObject.getError() as? IoError
|
||||||
|
|
||||||
assertThat(error).isInstanceOf(IO::class.java)
|
assertThat(error).isInstanceOf(IoError::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -177,9 +177,9 @@ class ApiTest {
|
||||||
mockWebServer.enqueue(MockResponse().apply { socketPolicy = SocketPolicy.DISCONNECT_AFTER_REQUEST })
|
mockWebServer.enqueue(MockResponse().apply { socketPolicy = SocketPolicy.DISCONNECT_AFTER_REQUEST })
|
||||||
val responseObject = runBlocking { api.getSiteSync() }
|
val responseObject = runBlocking { api.getSiteSync() }
|
||||||
|
|
||||||
val error = responseObject.getError() as? IO
|
val error = responseObject.getError() as? IoError
|
||||||
|
|
||||||
assertThat(error).isInstanceOf(IO::class.java)
|
assertThat(error).isInstanceOf(IoError::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -189,9 +189,9 @@ class ApiTest {
|
||||||
mockWebServer.enqueue(response)
|
mockWebServer.enqueue(response)
|
||||||
val responseObject = api.getSitesAsync().getError()
|
val responseObject = api.getSitesAsync().getError()
|
||||||
|
|
||||||
val error = responseObject as? JsonParse
|
val error = responseObject as? JsonParseError
|
||||||
|
|
||||||
assertThat(error).isInstanceOf(JsonParse::class.java)
|
assertThat(error).isInstanceOf(JsonParseError::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -201,11 +201,11 @@ class ApiTest {
|
||||||
|
|
||||||
val responseObject = api.getSitesAsync().getError()
|
val responseObject = api.getSitesAsync().getError()
|
||||||
|
|
||||||
val error = responseObject as? IO
|
val error = responseObject as? IoError
|
||||||
|
|
||||||
// Moshi reports invalid JSON as an IoException wrapping a JsonEncodingException
|
// Moshi reports invalid JSON as an IoException wrapping a JsonEncodingException
|
||||||
assertThat(error).isInstanceOf(IO::class.java)
|
assertThat(error).isInstanceOf(IoError::class.java)
|
||||||
assertThat(error?.throwable).isInstanceOf(JsonEncodingException::class.java)
|
assertThat(error?.exception).isInstanceOf(JsonEncodingException::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -32,6 +32,7 @@ import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import app.pachli.core.common.PachliError
|
||||||
import app.pachli.core.common.extensions.visible
|
import app.pachli.core.common.extensions.visible
|
||||||
import app.pachli.core.ui.databinding.ViewBackgroundMessageBinding
|
import app.pachli.core.ui.databinding.ViewBackgroundMessageBinding
|
||||||
import app.pachli.core.ui.extensions.getDrawableRes
|
import app.pachli.core.ui.extensions.getDrawableRes
|
||||||
|
@ -99,6 +100,10 @@ class BackgroundMessageView @JvmOverloads constructor(
|
||||||
setup(throwable.getDrawableRes(), throwable.getErrorString(context), listener)
|
setup(throwable.getDrawableRes(), throwable.getErrorString(context), listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setup(error: PachliError, listener: ((v: View) -> Unit)? = null) {
|
||||||
|
setup(error.getDrawableRes(), error.fmt(context), listener)
|
||||||
|
}
|
||||||
|
|
||||||
fun setup(message: BackgroundMessage, listener: ((v: View) -> Unit)? = null) {
|
fun setup(message: BackgroundMessage, listener: ((v: View) -> Unit)? = null) {
|
||||||
setup(message.drawableRes, message.stringRes, listener)
|
setup(message.drawableRes, message.stringRes, listener)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Pachli Association
|
||||||
|
*
|
||||||
|
* This file is a part of Pachli.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package app.pachli.core.ui.extensions
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import app.pachli.core.common.PachliError
|
||||||
|
import app.pachli.core.network.retrofit.apiresult.ClientError
|
||||||
|
import app.pachli.core.network.retrofit.apiresult.HttpError
|
||||||
|
import app.pachli.core.network.retrofit.apiresult.IoError
|
||||||
|
import app.pachli.core.ui.R
|
||||||
|
|
||||||
|
/** @return A drawable resource to accompany the error message for this [PachliError]. */
|
||||||
|
@DrawableRes
|
||||||
|
fun PachliError.getDrawableRes(): Int = when (this) {
|
||||||
|
is IoError -> R.drawable.errorphant_offline
|
||||||
|
is HttpError -> when (this) {
|
||||||
|
is ClientError.NotFound -> R.drawable.elephant_friend_empty
|
||||||
|
else -> R.drawable.errorphant_offline
|
||||||
|
}
|
||||||
|
else -> R.drawable.errorphant_offline
|
||||||
|
}
|
|
@ -18,7 +18,9 @@
|
||||||
package app.pachli.core.ui.extensions
|
package app.pachli.core.ui.extensions
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
import app.pachli.core.common.string.unicodeWrap
|
import app.pachli.core.common.string.unicodeWrap
|
||||||
|
import app.pachli.core.network.R as NR
|
||||||
import app.pachli.core.network.extensions.getServerErrorMessage
|
import app.pachli.core.network.extensions.getServerErrorMessage
|
||||||
import app.pachli.core.ui.R
|
import app.pachli.core.ui.R
|
||||||
import com.squareup.moshi.JsonDataException
|
import com.squareup.moshi.JsonDataException
|
||||||
|
@ -26,6 +28,7 @@ import java.io.IOException
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
|
||||||
/** @return A drawable resource to accompany the error message for this throwable */
|
/** @return A drawable resource to accompany the error message for this throwable */
|
||||||
|
@DrawableRes
|
||||||
fun Throwable.getDrawableRes(): Int = when (this) {
|
fun Throwable.getDrawableRes(): Int = when (this) {
|
||||||
is IOException -> R.drawable.errorphant_offline
|
is IOException -> R.drawable.errorphant_offline
|
||||||
is HttpException -> {
|
is HttpException -> {
|
||||||
|
@ -41,15 +44,15 @@ fun Throwable.getDrawableRes(): Int = when (this) {
|
||||||
/** @return A unicode-wrapped string error message for this throwable */
|
/** @return A unicode-wrapped string error message for this throwable */
|
||||||
fun Throwable.getErrorString(context: Context): String = (
|
fun Throwable.getErrorString(context: Context): String = (
|
||||||
getServerErrorMessage() ?: when (this) {
|
getServerErrorMessage() ?: when (this) {
|
||||||
is IOException -> String.format(context.getString(R.string.error_network_fmt), localizedMessage)
|
is IOException -> String.format(context.getString(NR.string.error_network_fmt), localizedMessage)
|
||||||
is HttpException -> {
|
is HttpException -> {
|
||||||
if (code() == 404) {
|
if (code() == 404) {
|
||||||
String.format(context.getString(R.string.error_404_not_found_fmt), localizedMessage)
|
String.format(context.getString(NR.string.error_404_not_found_fmt), localizedMessage)
|
||||||
} else {
|
} else {
|
||||||
String.format(context.getString(R.string.error_generic_fmt), localizedMessage)
|
String.format(context.getString(NR.string.error_generic_fmt), localizedMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is JsonDataException -> String.format(context.getString(R.string.error_json_data_fmt), localizedMessage)
|
is JsonDataException -> String.format(context.getString(NR.string.error_json_data_fmt), localizedMessage)
|
||||||
else -> String.format(context.getString(R.string.error_generic_fmt), localizedMessage)
|
else -> String.format(context.getString(NR.string.error_generic_fmt), localizedMessage)
|
||||||
}
|
}
|
||||||
).unicodeWrap()
|
).unicodeWrap()
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">حدث خطأ في الشبكة! يرجى التحقق من اتصالك ثم أعد المحاولة!</string>
|
<string name="error_network">حدث خطأ في الشبكة! يرجى التحقق من اتصالك ثم أعد المحاولة!</string>
|
||||||
<string name="error_network_fmt">وقع خطأ في الشبكة: %s</string>
|
|
||||||
<string name="error_generic_fmt">وقع خطأ: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">خادمك لا يدعم هذه الميزة: %1$s</string>
|
|
||||||
<string name="error_generic">وقع هناك خطأ.</string>
|
<string name="error_generic">وقع هناك خطأ.</string>
|
||||||
<string name="message_empty">لا شيء هنا.</string>
|
<string name="message_empty">لا شيء هنا.</string>
|
||||||
<string name="action_retry">أعد المحاولة</string>
|
<string name="action_retry">أعد المحاولة</string>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Ein Netzwerkfehler ist aufgetreten. Bitte überprüfe deine Internetverbindung und versuche es erneut.</string>
|
<string name="error_network">Ein Netzwerkfehler ist aufgetreten. Bitte überprüfe deine Internetverbindung und versuche es erneut.</string>
|
||||||
<string name="error_network_fmt">Ein Netzwerkfehler ist aufgetreten: %s</string>
|
|
||||||
<string name="error_generic_fmt">Es ist ein Fehler aufgetreten: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Dein Server unterstützt diese Funktion nicht: %1$s</string>
|
|
||||||
<string name="error_generic">Ein Fehler ist aufgetreten.</string>
|
<string name="error_generic">Ein Fehler ist aufgetreten.</string>
|
||||||
<string name="message_empty">Hier ist nichts.</string>
|
<string name="message_empty">Hier ist nichts.</string>
|
||||||
<string name="action_retry">Erneut versuchen</string>
|
<string name="action_retry">Erneut versuchen</string>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">A network error occurred! Please check your connection and try again!</string>
|
<string name="error_network">A network error occurred! Please check your connection and try again!</string>
|
||||||
<string name="error_generic_fmt">An error occurred: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Your server does not support this feature: %1$s</string>
|
|
||||||
<string name="error_generic">An error occurred.</string>
|
<string name="error_generic">An error occurred.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Ha ocurrido un error de red. Por favor, comprueba tu conexión e inténtalo de nuevo.</string>
|
<string name="error_network">Ha ocurrido un error de red. Por favor, comprueba tu conexión e inténtalo de nuevo.</string>
|
||||||
<string name="error_network_fmt">Ha ocurrido un error de red: %s</string>
|
|
||||||
<string name="error_generic_fmt">Ha ocurrido un error: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Su servidor no soporta esta función: %1$s</string>
|
|
||||||
<string name="error_generic">Ha ocurrido un error.</string>
|
<string name="error_generic">Ha ocurrido un error.</string>
|
||||||
<string name="message_empty">Nada aquí.</string>
|
<string name="message_empty">Nada aquí.</string>
|
||||||
<string name="action_retry">Reintentar</string>
|
<string name="action_retry">Reintentar</string>
|
||||||
|
@ -11,6 +8,5 @@
|
||||||
<string name="action_view_profile">Perfil</string>
|
<string name="action_view_profile">Perfil</string>
|
||||||
<string name="action_more">Más</string>
|
<string name="action_more">Más</string>
|
||||||
<string name="action_refresh">Recargar</string>
|
<string name="action_refresh">Recargar</string>
|
||||||
<string name="error_json_data_fmt">Tu servidor devolvió una respuesta inválida: %1$s</string>
|
|
||||||
<string name="url_domain_notifier">\u0020(🔗 %s)</string>
|
<string name="url_domain_notifier">\u0020(🔗 %s)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Verkkovirhe. Tarkista yhteytesi ja yritä uudelleen.</string>
|
<string name="error_network">Verkkovirhe. Tarkista yhteytesi ja yritä uudelleen.</string>
|
||||||
<string name="error_network_fmt">Tapahtui verkkovirhe: %s</string>
|
|
||||||
<string name="error_generic_fmt">Tapahtui virhe: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Palvelimesi ei tue tätä ominaisuutta: %1$s</string>
|
|
||||||
<string name="error_generic">Tapahtui virhe.</string>
|
<string name="error_generic">Tapahtui virhe.</string>
|
||||||
<string name="message_empty">Täällä ei ole mitään.</string>
|
<string name="message_empty">Täällä ei ole mitään.</string>
|
||||||
<string name="action_retry">Yritä uudelleen</string>
|
<string name="action_retry">Yritä uudelleen</string>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Une erreur réseau s’est produite ! Veuillez vérifier votre connexion puis réessayez !</string>
|
<string name="error_network">Une erreur réseau s’est produite ! Veuillez vérifier votre connexion puis réessayez !</string>
|
||||||
<string name="error_network_fmt">Une erreur réseau s\'est produite : %s</string>
|
|
||||||
<string name="error_generic_fmt">Une erreur s\'est produite : %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Votre serveur ne prend pas en charge cette fonctionnalité: %1$s</string>
|
|
||||||
<string name="error_generic">Une erreur s’est produite.</string>
|
<string name="error_generic">Une erreur s’est produite.</string>
|
||||||
<string name="message_empty">Rien ici.</string>
|
<string name="message_empty">Rien ici.</string>
|
||||||
<string name="action_retry">Réessayer</string>
|
<string name="action_retry">Réessayer</string>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Terjadi kesalahan pada jaringan! Harap periksa koneksi Anda dan coba lagi!</string>
|
<string name="error_network">Terjadi kesalahan pada jaringan! Harap periksa koneksi Anda dan coba lagi!</string>
|
||||||
<string name="error_network_fmt">Jaringan error: %s</string>
|
|
||||||
<string name="error_generic_fmt">Terjadi error: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Server Anda tidak mendukung fitur ini: %1$s</string>
|
|
||||||
<string name="error_generic">Terjadi kesalahan.</string>
|
<string name="error_generic">Terjadi kesalahan.</string>
|
||||||
<string name="message_empty">Tidak ada apa pun disini.</string>
|
<string name="message_empty">Tidak ada apa pun disini.</string>
|
||||||
<string name="action_retry">Coba lagi</string>
|
<string name="action_retry">Coba lagi</string>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Si è verificato un errore di rete. Per favore controlla la tua connessione e riprova.</string>
|
<string name="error_network">Si è verificato un errore di rete. Per favore controlla la tua connessione e riprova.</string>
|
||||||
<string name="error_network_fmt">Si è verificato un errore di rete: %s</string>
|
|
||||||
<string name="error_generic_fmt">Si è verificato un errore: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Il tuo server non supporta questa feature: %1$s</string>
|
|
||||||
<string name="error_generic">Si è verificato un errore.</string>
|
<string name="error_generic">Si è verificato un errore.</string>
|
||||||
<string name="message_empty">Qui non c\'è nulla.</string>
|
<string name="message_empty">Qui non c\'è nulla.</string>
|
||||||
<string name="action_retry">Riprova</string>
|
<string name="action_retry">Riprova</string>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">ネットワークエラーが発生しました。接続を確認してもう一度試してください。</string>
|
<string name="error_network">ネットワークエラーが発生しました。接続を確認してもう一度試してください。</string>
|
||||||
<string name="error_network_fmt">ネットワーク エラーが発生しました: %s</string>
|
|
||||||
<string name="error_generic_fmt">エラーが発生しました: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">あなたのサーバーはこの機能をサポートしていません: %1$s</string>
|
|
||||||
<string name="error_generic">エラーが発生しました。</string>
|
<string name="error_generic">エラーが発生しました。</string>
|
||||||
<string name="message_empty">何もありません。</string>
|
<string name="message_empty">何もありません。</string>
|
||||||
<string name="action_retry">再試行</string>
|
<string name="action_retry">再試行</string>
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<string name="action_retry">Ɛreḍ tikkelt-nniḍen</string>
|
<string name="action_retry">Ɛreḍ tikkelt-nniḍen</string>
|
||||||
<string name="action_view_profile">Amaɣnu</string>
|
<string name="action_view_profile">Amaɣnu</string>
|
||||||
<string name="action_more">Ugar</string>
|
<string name="action_more">Ugar</string>
|
||||||
<string name="error_generic_fmt">Tella-d tuccḍa: %s</string>
|
|
||||||
<string name="action_refresh">Smiren</string>
|
<string name="action_refresh">Smiren</string>
|
||||||
<string name="button_done">Immed</string>
|
<string name="button_done">Immed</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Er deed zich een netwerkfout voor. Controleer je verbinding en probeer opnieuw.</string>
|
<string name="error_network">Er deed zich een netwerkfout voor. Controleer je verbinding en probeer opnieuw.</string>
|
||||||
<string name="error_network_fmt">Er deed zich een netwerkfout voor: %s</string>
|
|
||||||
<string name="error_generic_fmt">Er deed zich een fout voor: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Je server beschikt niet over ondersteuning voor deze feature: %1$s</string>
|
|
||||||
<string name="error_generic">Er deed zich een fout voor.</string>
|
<string name="error_generic">Er deed zich een fout voor.</string>
|
||||||
<string name="message_empty">Hier is niets.</string>
|
<string name="message_empty">Hier is niets.</string>
|
||||||
<string name="action_retry">Opnieuw proberen</string>
|
<string name="action_retry">Opnieuw proberen</string>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Ocorreu um erro de rede. Por favor, verifique tua Internet e tente novamente.</string>
|
<string name="error_network">Ocorreu um erro de rede. Por favor, verifique tua Internet e tente novamente.</string>
|
||||||
<string name="error_network_fmt">Ocorreu um erro de rede: %s</string>
|
|
||||||
<string name="error_generic_fmt">Ocorreu um erro: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Tua instância não suporta este recurso: %1$s</string>
|
|
||||||
<string name="error_generic">Um erro ocorreu.</string>
|
<string name="error_generic">Um erro ocorreu.</string>
|
||||||
<string name="message_empty">Nada aqui.</string>
|
<string name="message_empty">Nada aqui.</string>
|
||||||
<string name="action_retry">Tentar novamente</string>
|
<string name="action_retry">Tentar novamente</string>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">Ett nätverksfel uppstod. Kontrollera din anslutning och försök igen.</string>
|
<string name="error_network">Ett nätverksfel uppstod. Kontrollera din anslutning och försök igen.</string>
|
||||||
<string name="error_network_fmt">Ett nätverksfel har uppstått: %s</string>
|
|
||||||
<string name="error_generic_fmt">Ett fel har uppstått: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Din server stöder inte denna funktion: %1$s</string>
|
|
||||||
<string name="error_generic">Ett fel har uppstått.</string>
|
<string name="error_generic">Ett fel har uppstått.</string>
|
||||||
<string name="message_empty">Ingenting här.</string>
|
<string name="message_empty">Ingenting här.</string>
|
||||||
<string name="action_retry">Försök igen</string>
|
<string name="action_retry">Försök igen</string>
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="error_network">A network error occurred. Please check your connection and try again.</string>
|
<string name="error_network">A network error occurred. Please check your connection and try again.</string>
|
||||||
<string name="error_network_fmt">A network error occurred: %s</string>
|
|
||||||
<string name="error_generic_fmt">An error occurred: %s</string>
|
|
||||||
<string name="error_404_not_found_fmt">Your server does not support this feature: %1$s</string>
|
|
||||||
<string name="error_json_data_fmt">Your server returned an invalid response: %1$s</string>
|
|
||||||
<string name="error_generic">An error occurred.</string>
|
<string name="error_generic">An error occurred.</string>
|
||||||
<string name="message_empty">Nothing here.</string>
|
<string name="message_empty">Nothing here.</string>
|
||||||
<string name="action_retry">Retry</string>
|
<string name="action_retry">Retry</string>
|
||||||
|
|
|
@ -34,6 +34,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import app.pachli.core.activity.emojify
|
import app.pachli.core.activity.emojify
|
||||||
import app.pachli.core.activity.loadAvatar
|
import app.pachli.core.activity.loadAvatar
|
||||||
|
import app.pachli.core.common.PachliError
|
||||||
import app.pachli.core.common.extensions.hide
|
import app.pachli.core.common.extensions.hide
|
||||||
import app.pachli.core.common.extensions.show
|
import app.pachli.core.common.extensions.show
|
||||||
import app.pachli.core.common.extensions.viewBinding
|
import app.pachli.core.common.extensions.viewBinding
|
||||||
|
@ -141,7 +142,7 @@ class AccountsInListFragment : DialogFragment() {
|
||||||
|
|
||||||
launch {
|
launch {
|
||||||
viewModel.errors.collect {
|
viewModel.errors.collect {
|
||||||
handleError(it.throwable)
|
handleError(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +173,7 @@ class AccountsInListFragment : DialogFragment() {
|
||||||
if (it is Accounts.Loaded) adapter.submitList(it.accounts)
|
if (it is Accounts.Loaded) adapter.submitList(it.accounts)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
binding.messageView.show()
|
binding.messageView.show()
|
||||||
handleError(it.throwable)
|
handleError(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,11 +197,11 @@ class AccountsInListFragment : DialogFragment() {
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
Timber.w(it.throwable, "Error searching for accounts in list")
|
Timber.w(it.throwable, "Error searching for accounts in list")
|
||||||
handleError(it.throwable)
|
handleError(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleError(error: Throwable) {
|
private fun handleError(error: PachliError) {
|
||||||
binding.messageView.show()
|
binding.messageView.show()
|
||||||
binding.messageView.setup(error) {
|
binding.messageView.setup(error) {
|
||||||
binding.messageView.hide()
|
binding.messageView.hide()
|
||||||
|
|
|
@ -43,14 +43,12 @@ import app.pachli.core.activity.extensions.startActivityWithDefaultTransition
|
||||||
import app.pachli.core.common.extensions.hide
|
import app.pachli.core.common.extensions.hide
|
||||||
import app.pachli.core.common.extensions.show
|
import app.pachli.core.common.extensions.show
|
||||||
import app.pachli.core.common.extensions.viewBinding
|
import app.pachli.core.common.extensions.viewBinding
|
||||||
import app.pachli.core.common.string.unicodeWrap
|
|
||||||
import app.pachli.core.data.repository.Lists
|
import app.pachli.core.data.repository.Lists
|
||||||
|
import app.pachli.core.data.repository.ListsError
|
||||||
import app.pachli.core.data.repository.ListsRepository.Companion.compareByListTitle
|
import app.pachli.core.data.repository.ListsRepository.Companion.compareByListTitle
|
||||||
import app.pachli.core.navigation.TimelineActivityIntent
|
import app.pachli.core.navigation.TimelineActivityIntent
|
||||||
import app.pachli.core.network.model.MastoList
|
import app.pachli.core.network.model.MastoList
|
||||||
import app.pachli.core.network.model.UserListRepliesPolicy
|
import app.pachli.core.network.model.UserListRepliesPolicy
|
||||||
import app.pachli.core.network.retrofit.apiresult.ApiError
|
|
||||||
import app.pachli.core.network.retrofit.apiresult.NetworkError
|
|
||||||
import app.pachli.core.ui.BackgroundMessage
|
import app.pachli.core.ui.BackgroundMessage
|
||||||
import app.pachli.core.ui.extensions.await
|
import app.pachli.core.ui.extensions.await
|
||||||
import app.pachli.feature.lists.databinding.ActivityListsBinding
|
import app.pachli.feature.lists.databinding.ActivityListsBinding
|
||||||
|
@ -113,29 +111,7 @@ class ListsActivity : BaseActivity(), MenuProvider {
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.errors.collect { error ->
|
viewModel.errors.collect { error ->
|
||||||
when (error) {
|
showMessage(error.fmt(this@ListsActivity))
|
||||||
is Error.Create -> showMessage(
|
|
||||||
String.format(
|
|
||||||
getString(R.string.error_create_list_fmt),
|
|
||||||
error.title.unicodeWrap(),
|
|
||||||
error.throwable.message.unicodeWrap(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
is Error.Delete -> showMessage(
|
|
||||||
String.format(
|
|
||||||
getString(R.string.error_delete_list_fmt),
|
|
||||||
error.title.unicodeWrap(),
|
|
||||||
error.throwable.message.unicodeWrap(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
is Error.Update -> showMessage(
|
|
||||||
String.format(
|
|
||||||
getString(R.string.error_rename_list_fmt),
|
|
||||||
error.title.unicodeWrap(),
|
|
||||||
error.throwable.message.unicodeWrap(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,17 +196,13 @@ class ListsActivity : BaseActivity(), MenuProvider {
|
||||||
if (result == AlertDialog.BUTTON_POSITIVE) viewModel.deleteList(list.id, list.title)
|
if (result == AlertDialog.BUTTON_POSITIVE) viewModel.deleteList(list.id, list.title)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bind(state: Result<Lists, ApiError>) {
|
private fun bind(state: Result<Lists, ListsError>) {
|
||||||
state.onFailure {
|
state.onFailure {
|
||||||
binding.listsRecycler.hide()
|
binding.listsRecycler.hide()
|
||||||
binding.messageView.show()
|
binding.messageView.show()
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
|
|
||||||
if (it is NetworkError) {
|
binding.messageView.setup(it) { viewModel.refresh() }
|
||||||
binding.messageView.setup(BackgroundMessage.Network()) { viewModel.refresh() }
|
|
||||||
} else {
|
|
||||||
binding.messageView.setup(BackgroundMessage.GenericError()) { viewModel.refresh() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.onSuccess { lists ->
|
state.onSuccess { lists ->
|
||||||
|
|
|
@ -155,7 +155,7 @@ class ListsForAccountFragment : DialogFragment() {
|
||||||
binding.listsView.hide()
|
binding.listsView.hide()
|
||||||
binding.messageView.apply {
|
binding.messageView.apply {
|
||||||
show()
|
show()
|
||||||
setup(it.throwable) {
|
setup(it) {
|
||||||
viewModel.refresh()
|
viewModel.refresh()
|
||||||
load()
|
load()
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import app.pachli.core.data.repository.Lists
|
||||||
import app.pachli.core.data.repository.ListsError
|
import app.pachli.core.data.repository.ListsError
|
||||||
import app.pachli.core.data.repository.ListsRepository
|
import app.pachli.core.data.repository.ListsRepository
|
||||||
import app.pachli.core.network.model.MastoList
|
import app.pachli.core.network.model.MastoList
|
||||||
import app.pachli.core.network.retrofit.apiresult.ApiError
|
|
||||||
import com.github.michaelbull.result.Err
|
import com.github.michaelbull.result.Err
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
import com.github.michaelbull.result.Result
|
import com.github.michaelbull.result.Result
|
||||||
|
@ -67,7 +66,7 @@ class ListsForAccountViewModel @AssistedInject constructor(
|
||||||
private val _listsWithMembership = MutableStateFlow<Result<ListsWithMembership, FlowError>>(Ok(ListsWithMembership.Loading))
|
private val _listsWithMembership = MutableStateFlow<Result<ListsWithMembership, FlowError>>(Ok(ListsWithMembership.Loading))
|
||||||
val listsWithMembership = _listsWithMembership.asStateFlow()
|
val listsWithMembership = _listsWithMembership.asStateFlow()
|
||||||
|
|
||||||
private val _errors = Channel<Error>()
|
private val _errors = Channel<HasListId>()
|
||||||
val errors = _errors.receiveAsFlow()
|
val errors = _errors.receiveAsFlow()
|
||||||
|
|
||||||
private val listsWithMembershipMap = mutableMapOf<String, ListWithMembership>()
|
private val listsWithMembershipMap = mutableMapOf<String, ListWithMembership>()
|
||||||
|
@ -164,21 +163,21 @@ class ListsForAccountViewModel @AssistedInject constructor(
|
||||||
* Marker for errors that can be part of the [Result] in the
|
* Marker for errors that can be part of the [Result] in the
|
||||||
* [ListsForAccountViewModel.listsWithMembership] flow
|
* [ListsForAccountViewModel.listsWithMembership] flow
|
||||||
*/
|
*/
|
||||||
sealed interface FlowError : ApiError
|
sealed interface FlowError : Error
|
||||||
|
|
||||||
/** Asynchronous errors from network operations */
|
/** Asynchronous errors from network operations */
|
||||||
sealed interface Error : ListsError {
|
sealed interface Error : ListsError {
|
||||||
/** Failed to fetch lists, or lists containing a particular account */
|
/** Failed to fetch lists, or lists containing a particular account */
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class GetListsWithAccount(val error: ListsError.GetListsWithAccount) : FlowError, ListsError by error
|
value class GetListsWithAccount(private val error: ListsError.GetListsWithAccount) : FlowError, Error, ListsError by error
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Retrieve(val error: ListsError.Retrieve) : FlowError, ListsError by error
|
value class Retrieve(private val error: ListsError.Retrieve) : FlowError, Error, ListsError by error
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class AddAccounts(val error: ListsError.AddAccounts) : Error, HasListId by error, ListsError by error
|
value class AddAccounts(private val error: ListsError.AddAccounts) : Error, HasListId by error, ListsError by error
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class DeleteAccounts(val error: ListsError.DeleteAccounts) : Error, HasListId by error, ListsError by error
|
value class DeleteAccounts(private val error: ListsError.DeleteAccounts) : Error, HasListId by error, ListsError by error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
|
|
||||||
package app.pachli.feature.lists
|
package app.pachli.feature.lists
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import app.pachli.core.common.string.unicodeWrap
|
||||||
import app.pachli.core.data.repository.ListsError
|
import app.pachli.core.data.repository.ListsError
|
||||||
import app.pachli.core.data.repository.ListsRepository
|
import app.pachli.core.data.repository.ListsRepository
|
||||||
import app.pachli.core.network.model.UserListRepliesPolicy
|
import app.pachli.core.network.model.UserListRepliesPolicy
|
||||||
|
@ -32,14 +34,20 @@ import kotlinx.coroutines.flow.getAndUpdate
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
sealed interface Error : ListsError {
|
sealed class Error(
|
||||||
val title: String
|
@StringRes override val resourceId: Int,
|
||||||
|
override val formatArgs: Array<out String>,
|
||||||
|
override val cause: ListsError? = null,
|
||||||
|
) : ListsError {
|
||||||
|
|
||||||
data class Create(override val title: String, private val error: ListsError.Create) : Error, ListsError by error
|
data class Create(val title: String, override val cause: ListsError.Create) :
|
||||||
|
Error(R.string.error_create_list_fmt, arrayOf(title.unicodeWrap()), cause)
|
||||||
|
|
||||||
data class Delete(override val title: String, private val error: ListsError.Delete) : Error, ListsError by error
|
data class Delete(val title: String, override val cause: ListsError.Delete) :
|
||||||
|
Error(R.string.error_delete_list_fmt, arrayOf(title.unicodeWrap()), cause)
|
||||||
|
|
||||||
data class Update(override val title: String, private val error: ListsError.Update) : Error, ListsError by error
|
data class Update(val title: String, override val cause: ListsError.Update) :
|
||||||
|
Error(R.string.error_rename_list_fmt, arrayOf(title.unicodeWrap()), cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
|
|
Loading…
Reference in New Issue