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=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="133"
|
||||
line="132"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -168,7 +168,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-sl/strings.xml"
|
||||
line="180"
|
||||
line="179"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -179,7 +179,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="194"
|
||||
line="193"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -190,7 +190,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-bn-rIN/strings.xml"
|
||||
line="201"
|
||||
line="200"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -212,7 +212,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-sl/strings.xml"
|
||||
line="214"
|
||||
line="213"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -223,7 +223,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="236"
|
||||
line="235"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -234,7 +234,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="237"
|
||||
line="236"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -245,7 +245,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-bn-rIN/strings.xml"
|
||||
line="242"
|
||||
line="241"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -267,7 +267,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-hi/strings.xml"
|
||||
line="270"
|
||||
line="269"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -278,7 +278,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="273"
|
||||
line="272"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -289,21 +289,21 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
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"
|
||||
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="278"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="MissingQuantity"
|
||||
message="For locale "cs" (Czech) the following quantity should also be defined: `many` (e.g. "10.0 dne")"
|
||||
|
@ -311,7 +311,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="283"
|
||||
line="282"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -322,7 +322,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="302"
|
||||
line="301"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -333,7 +333,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="313"
|
||||
line="312"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -344,7 +344,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="327"
|
||||
line="326"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -355,7 +355,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="332"
|
||||
line="331"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -366,7 +366,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="337"
|
||||
line="336"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -377,7 +377,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-bg/strings.xml"
|
||||
line="369"
|
||||
line="368"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -388,7 +388,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="369"
|
||||
line="368"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -399,7 +399,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="397"
|
||||
line="396"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -410,7 +410,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="401"
|
||||
line="400"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -421,7 +421,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="405"
|
||||
line="404"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -432,7 +432,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="409"
|
||||
line="408"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -443,7 +443,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="417"
|
||||
line="416"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -454,7 +454,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="422"
|
||||
line="421"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -465,7 +465,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-ca/strings.xml"
|
||||
line="425"
|
||||
line="424"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -476,7 +476,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-cs/strings.xml"
|
||||
line="427"
|
||||
line="426"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -509,7 +509,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="34"
|
||||
line="33"
|
||||
column="44"/>
|
||||
</issue>
|
||||
|
||||
|
@ -520,7 +520,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-tr/strings.xml"
|
||||
line="40"
|
||||
line="39"
|
||||
column="50"/>
|
||||
</issue>
|
||||
|
||||
|
@ -531,7 +531,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-tr/strings.xml"
|
||||
line="40"
|
||||
line="39"
|
||||
column="46"/>
|
||||
</issue>
|
||||
|
||||
|
@ -542,7 +542,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="71"
|
||||
line="70"
|
||||
column="38"/>
|
||||
</issue>
|
||||
|
||||
|
@ -553,7 +553,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="73"
|
||||
line="72"
|
||||
column="46"/>
|
||||
</issue>
|
||||
|
||||
|
@ -564,7 +564,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="79"
|
||||
line="78"
|
||||
column="44"/>
|
||||
</issue>
|
||||
|
||||
|
@ -575,7 +575,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="102"
|
||||
line="101"
|
||||
column="45"/>
|
||||
</issue>
|
||||
|
||||
|
@ -586,7 +586,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="106"
|
||||
line="105"
|
||||
column="44"/>
|
||||
</issue>
|
||||
|
||||
|
@ -597,7 +597,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="107"
|
||||
line="106"
|
||||
column="49"/>
|
||||
</issue>
|
||||
|
||||
|
@ -608,7 +608,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="110"
|
||||
line="109"
|
||||
column="38"/>
|
||||
</issue>
|
||||
|
||||
|
@ -619,7 +619,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="125"
|
||||
line="124"
|
||||
column="70"/>
|
||||
</issue>
|
||||
|
||||
|
@ -630,7 +630,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="158"
|
||||
line="157"
|
||||
column="78"/>
|
||||
</issue>
|
||||
|
||||
|
@ -641,7 +641,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="164"
|
||||
line="163"
|
||||
column="65"/>
|
||||
</issue>
|
||||
|
||||
|
@ -652,7 +652,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="200"
|
||||
line="199"
|
||||
column="32"/>
|
||||
</issue>
|
||||
|
||||
|
@ -663,7 +663,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="268"
|
||||
line="267"
|
||||
column="43"/>
|
||||
</issue>
|
||||
|
||||
|
@ -674,7 +674,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="396"
|
||||
line="395"
|
||||
column="86"/>
|
||||
</issue>
|
||||
|
||||
|
@ -685,7 +685,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-tr/strings.xml"
|
||||
line="504"
|
||||
line="503"
|
||||
column="294"/>
|
||||
</issue>
|
||||
|
||||
|
@ -696,7 +696,7 @@
|
|||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/res/values-nb-rNO/strings.xml"
|
||||
line="526"
|
||||
line="525"
|
||||
column="51"/>
|
||||
</issue>
|
||||
|
||||
|
@ -729,7 +729,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="101"
|
||||
line="100"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -740,7 +740,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="288"
|
||||
line="287"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -751,7 +751,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="339"
|
||||
line="338"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -762,7 +762,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="458"
|
||||
line="457"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -773,7 +773,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="633"
|
||||
line="632"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1290,7 +1290,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="76"
|
||||
line="75"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1301,7 +1301,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="82"
|
||||
line="81"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1312,7 +1312,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="103"
|
||||
line="102"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1323,7 +1323,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="111"
|
||||
line="110"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1334,7 +1334,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="145"
|
||||
line="144"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1345,7 +1345,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="204"
|
||||
line="203"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1356,7 +1356,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="225"
|
||||
line="224"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1367,7 +1367,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="226"
|
||||
line="225"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1378,7 +1378,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="249"
|
||||
line="248"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1389,7 +1389,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="278"
|
||||
line="277"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1400,7 +1400,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="349"
|
||||
line="348"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1411,7 +1411,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="389"
|
||||
line="388"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1422,7 +1422,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="425"
|
||||
line="424"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1433,7 +1433,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="428"
|
||||
line="427"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1444,7 +1444,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="429"
|
||||
line="428"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1455,7 +1455,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="430"
|
||||
line="429"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1466,7 +1466,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="431"
|
||||
line="430"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1477,7 +1477,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="432"
|
||||
line="431"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1488,7 +1488,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="444"
|
||||
line="443"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1499,7 +1499,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="445"
|
||||
line="444"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1510,7 +1510,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="496"
|
||||
line="495"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1521,7 +1521,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="497"
|
||||
line="496"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1532,7 +1532,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="508"
|
||||
line="507"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1543,7 +1543,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="509"
|
||||
line="508"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1554,7 +1554,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="510"
|
||||
line="509"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1565,7 +1565,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="512"
|
||||
line="511"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1576,7 +1576,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="550"
|
||||
line="549"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1587,7 +1587,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="591"
|
||||
line="590"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1598,7 +1598,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="597"
|
||||
line="596"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1609,7 +1609,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="625"
|
||||
line="624"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1620,7 +1620,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="639"
|
||||
line="638"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
@ -1631,7 +1631,7 @@
|
|||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/values/strings.xml"
|
||||
line="652"
|
||||
line="651"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ import java.util.regex.Pattern
|
|||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
||||
|
@ -332,7 +331,6 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener {
|
|||
selectListBinding.progressBar.hide()
|
||||
dialog.dismiss()
|
||||
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(
|
||||
R.string.server_repository_error,
|
||||
accountManager.activeAccount!!.domain,
|
||||
it.msg(requireContext()),
|
||||
it.fmt(requireContext()),
|
||||
)
|
||||
Timber.e(msg)
|
||||
try {
|
||||
|
|
|
@ -19,36 +19,41 @@ package app.pachli.core.common
|
|||
|
||||
import android.content.Context
|
||||
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
|
||||
* class hierarchy like so:
|
||||
*
|
||||
* ```kotlin
|
||||
* sealed class Error(
|
||||
* @StringRes resourceId: Int,
|
||||
* vararg formatArgs: String,
|
||||
* source: PachliError? = null,
|
||||
* ) : PachliError(resourceId, *formatArgs, source = source) {
|
||||
* @StringRes override val resourceId: Int,
|
||||
* override val formatArgs: Array<out String>,
|
||||
* cause: PachliError? = null,
|
||||
* ) : PachliError {
|
||||
* data object SomeProblem : Error(R.string.error_some_problem)
|
||||
* 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,
|
||||
* )
|
||||
* data class Fetch(val url: String, val e: PachliError) : Error(
|
||||
* R.string.error_fetch,
|
||||
* data class Fetch(val url: String, val cause: PachliError) : Error(
|
||||
* R.string.error_fetch, // "Could not fetch %1$s: %2$s"
|
||||
* url,
|
||||
* source = e,
|
||||
* cause = cause,
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* 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
|
||||
* error that was the actual cause.
|
||||
* In this example `SomeProblem` represents an error with no additional context.
|
||||
*
|
||||
* `OutOfRange` is an error relating to a single value with no underlying 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:
|
||||
*
|
||||
|
@ -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_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(
|
||||
@StringRes private val resourceId: Int,
|
||||
private vararg val formatArgs: String,
|
||||
val source: PachliError? = null,
|
||||
) {
|
||||
fun msg(context: Context): String {
|
||||
interface PachliError {
|
||||
/** String resource ID for the error message. */
|
||||
@get:StringRes
|
||||
val resourceId: Int
|
||||
|
||||
/** 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)
|
||||
source?.let { args.add(it.msg(context)) }
|
||||
return context.getString(resourceId, *args.toTypedArray())
|
||||
cause?.let { args.add(it.fmt(context)) }
|
||||
return context.getString(resourceId, *args.toTypedArray()).unicodeWrap()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
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.TimelineAccount
|
||||
import app.pachli.core.network.model.UserListRepliesPolicy
|
||||
|
@ -36,26 +37,26 @@ interface HasListId {
|
|||
}
|
||||
|
||||
/** Errors that can be returned from this repository */
|
||||
interface ListsError : ApiError {
|
||||
interface ListsError : PachliError {
|
||||
@JvmInline
|
||||
value class Create(private val error: ApiError) : ListsError, ApiError by error
|
||||
value class Create(private val error: ApiError) : ListsError, PachliError by error
|
||||
|
||||
@JvmInline
|
||||
value class Retrieve(private val error: ApiError) : ListsError, ApiError by error
|
||||
value class Retrieve(private val error: ApiError) : ListsError, PachliError by error
|
||||
|
||||
@JvmInline
|
||||
value class Update(private val error: ApiError) : ListsError, ApiError by error
|
||||
value class Update(private val error: ApiError) : ListsError, PachliError by error
|
||||
|
||||
@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 {
|
||||
|
|
|
@ -119,13 +119,14 @@ class ServerRepository @Inject constructor(
|
|||
}
|
||||
|
||||
sealed class Error(
|
||||
@StringRes resourceId: Int,
|
||||
vararg formatArgs: String,
|
||||
source: PachliError? = null,
|
||||
) : PachliError(resourceId, *formatArgs, source = source) {
|
||||
@StringRes override val resourceId: Int,
|
||||
override val formatArgs: Array<out String> = emptyArray<String>(),
|
||||
override val cause: PachliError? = null,
|
||||
) : PachliError {
|
||||
|
||||
data class GetWellKnownNodeInfo(val throwable: Throwable) : Error(
|
||||
R.string.server_repository_error_get_well_known_node_info,
|
||||
throwable.localizedMessage,
|
||||
throwable.localizedMessage?.let { arrayOf(it) }.orEmpty(),
|
||||
)
|
||||
|
||||
data object UnsupportedSchema : Error(
|
||||
|
@ -134,24 +135,23 @@ class ServerRepository @Inject constructor(
|
|||
|
||||
data class GetNodeInfo(val url: String, val throwable: Throwable) : Error(
|
||||
R.string.server_repository_error_get_node_info,
|
||||
url,
|
||||
throwable.localizedMessage,
|
||||
arrayOf(url, throwable.localizedMessage ?: ""),
|
||||
)
|
||||
|
||||
data class ValidateNodeInfo(val url: String, val error: NodeInfo.Error) : Error(
|
||||
R.string.server_repository_error_validate_node_info,
|
||||
url,
|
||||
source = error,
|
||||
arrayOf(url),
|
||||
cause = error,
|
||||
)
|
||||
|
||||
data class GetInstanceInfoV1(val throwable: Throwable) : Error(
|
||||
R.string.server_repository_error_get_instance_info,
|
||||
throwable.localizedMessage,
|
||||
throwable.localizedMessage?.let { arrayOf(it) }.orEmpty(),
|
||||
)
|
||||
|
||||
data class Capabilities(val error: Server.Error) : Error(
|
||||
R.string.server_repository_error_capabilities,
|
||||
source = error,
|
||||
cause = error,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?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>
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package app.pachli.core.network
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.annotation.VisibleForTesting.Companion.PRIVATE
|
||||
import app.pachli.core.common.PachliError
|
||||
|
@ -296,16 +295,13 @@ data class Server(
|
|||
}
|
||||
|
||||
/** Errors that can occur when processing server capabilities */
|
||||
sealed class Error(
|
||||
@StringRes resourceId: Int,
|
||||
vararg formatArgs: String,
|
||||
) : PachliError(resourceId, *formatArgs) {
|
||||
sealed interface Error : PachliError {
|
||||
/** Could not parse the server's version string */
|
||||
data class UnparseableVersion(val version: String, val throwable: Throwable) : Error(
|
||||
R.string.server_error_unparseable_version,
|
||||
version,
|
||||
throwable.localizedMessage,
|
||||
)
|
||||
data class UnparseableVersion(val version: String, val throwable: Throwable) : Error {
|
||||
override val resourceId = R.string.server_error_unparseable_version
|
||||
override val formatArgs: Array<String> = arrayOf(version, throwable.localizedMessage ?: "")
|
||||
override val cause: PachliError? = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -77,10 +77,11 @@ data class NodeInfo(val software: Software) {
|
|||
}
|
||||
|
||||
sealed class Error(
|
||||
@StringRes resourceId: Int,
|
||||
vararg formatArgs: String,
|
||||
source: PachliError? = null,
|
||||
) : PachliError(resourceId, *formatArgs, source = source) {
|
||||
@StringRes override val resourceId: Int,
|
||||
) : PachliError {
|
||||
override val formatArgs = emptyArray<String>()
|
||||
override val cause: PachliError? = null
|
||||
|
||||
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 NoSoftwareVersion : Error(R.string.node_info_error_no_software_version)
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
|
||||
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.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
|
@ -45,50 +49,57 @@ data class ApiResponse<out T>(
|
|||
|
||||
/**
|
||||
* 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 {
|
||||
// This has to be Throwable, not Exception, because Retrofit exposes
|
||||
// errors as Throwable
|
||||
val throwable: Throwable
|
||||
sealed class ApiError(
|
||||
@StringRes override val resourceId: Int,
|
||||
val throwable: Throwable,
|
||||
) : PachliError {
|
||||
override val formatArgs = (
|
||||
throwable.getServerErrorMessage() ?: throwable.localizedMessage
|
||||
)?.let { arrayOf(it) }.orEmpty()
|
||||
override val cause: PachliError? = null
|
||||
|
||||
companion object {
|
||||
fun from(exception: Throwable): ApiError {
|
||||
return when (exception) {
|
||||
is HttpException -> when (exception.code()) {
|
||||
in 400..499 -> ClientError.from(exception)
|
||||
in 500..599 -> ServerError.from(exception)
|
||||
else -> Unknown(exception)
|
||||
fun from(throwable: Throwable): ApiError {
|
||||
return when (throwable) {
|
||||
is HttpException -> when (throwable.code()) {
|
||||
in 400..499 -> ClientError.from(throwable)
|
||||
in 500..599 -> ServerError.from(throwable)
|
||||
else -> Unknown(throwable)
|
||||
}
|
||||
|
||||
is JsonDataException -> JsonParse(exception)
|
||||
is IOException -> IO(exception)
|
||||
else -> Unknown(exception)
|
||||
is JsonDataException -> JsonParseError(throwable)
|
||||
is IOException -> IoError(throwable)
|
||||
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 {
|
||||
override val throwable: HttpException
|
||||
|
||||
/**
|
||||
* 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"
|
||||
}
|
||||
sealed class HttpError(
|
||||
@StringRes override val resourceId: Int,
|
||||
open val exception: HttpException,
|
||||
) : ApiError(resourceId, exception)
|
||||
|
||||
/** 4xx errors */
|
||||
sealed interface ClientError : HttpError {
|
||||
sealed class ClientError(
|
||||
@StringRes override val resourceId: Int,
|
||||
exception: HttpException,
|
||||
) : HttpError(resourceId, exception) {
|
||||
companion object {
|
||||
fun from(exception: HttpException): ClientError {
|
||||
return when (exception.code()) {
|
||||
400 -> BadRequest(exception)
|
||||
401 -> Unauthorized(exception)
|
||||
404 -> NotFound(exception)
|
||||
410 -> Gone(exception)
|
||||
|
@ -97,14 +108,32 @@ sealed interface ClientError : HttpError {
|
|||
}
|
||||
}
|
||||
|
||||
data class Unauthorized(override val throwable: HttpException) : ClientError
|
||||
data class NotFound(override val throwable: HttpException) : ClientError
|
||||
data class Gone(override val throwable: HttpException) : ClientError
|
||||
data class UnknownClientError(override val throwable: HttpException) : ClientError
|
||||
/** 400 Bad request */
|
||||
data class BadRequest(override val exception: HttpException) :
|
||||
ClientError(R.string.error_generic_fmt, exception)
|
||||
|
||||
/** 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 */
|
||||
sealed interface ServerError : HttpError {
|
||||
sealed class ServerError(
|
||||
@StringRes override val resourceId: Int,
|
||||
exception: HttpException,
|
||||
) : HttpError(resourceId, exception) {
|
||||
companion object {
|
||||
fun from(exception: HttpException): ServerError {
|
||||
return when (exception.code()) {
|
||||
|
@ -117,15 +146,32 @@ sealed interface ServerError : HttpError {
|
|||
}
|
||||
}
|
||||
|
||||
data class Internal(override val throwable: HttpException) : ServerError
|
||||
data class NotImplemented(override val throwable: HttpException) : ServerError
|
||||
data class BadGateway(override val throwable: HttpException) : ServerError
|
||||
data class ServiceUnavailable(override val throwable: HttpException) : ServerError
|
||||
data class UnknownServerError(override val throwable: HttpException) : ServerError
|
||||
/** 500 Internal error */
|
||||
data class Internal(override val exception: HttpException) :
|
||||
ServerError(R.string.error_generic_fmt, exception)
|
||||
|
||||
/** 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 IO(override val throwable: Exception) : NetworkError
|
||||
|
||||
data class JsonParseError(val exception: JsonDataException) :
|
||||
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].
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
<?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"?>
|
||||
<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"?>
|
||||
<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="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>
|
||||
</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"?>
|
||||
<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"?>
|
||||
<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"?>
|
||||
<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"?>
|
||||
<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"?>
|
||||
<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"?>
|
||||
<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_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>
|
||||
</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"?>
|
||||
<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_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>
|
||||
</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="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>
|
||||
|
|
|
@ -89,11 +89,10 @@ class ApiResultCallTest {
|
|||
override fun onResponse(call: Call<ApiResult<String>>, response: Response<ApiResult<String>>) {
|
||||
val error = response.body()?.getError() as? ClientError.NotFound
|
||||
assertThat(error).isInstanceOf(ClientError.NotFound::class.java)
|
||||
assertThat(error?.message).isEqualTo("not found")
|
||||
|
||||
val throwable = error?.throwable
|
||||
assertThat(throwable).isInstanceOf(HttpException::class.java)
|
||||
assertThat(throwable?.code()).isEqualTo(404)
|
||||
val exception = error?.exception
|
||||
assertThat(exception).isInstanceOf(HttpException::class.java)
|
||||
assertThat(exception?.code()).isEqualTo(404)
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<ApiResult<String>>, t: Throwable) {
|
||||
|
@ -107,7 +106,7 @@ class ApiResultCallTest {
|
|||
|
||||
@Test
|
||||
fun `should parse call with IOException as ApiResult-failure`() {
|
||||
val error = Err(IO(IOException()))
|
||||
val error = Err(IoError(IOException()))
|
||||
|
||||
networkApiResultCall.enqueue(
|
||||
object : Callback<ApiResult<String>> {
|
||||
|
|
|
@ -140,8 +140,8 @@ class ApiTest {
|
|||
|
||||
val error = responseObject as? ServerError.Internal
|
||||
assertThat(error).isInstanceOf(ServerError.Internal::class.java)
|
||||
assertThat(error?.throwable?.code()).isEqualTo(500)
|
||||
assertThat(error?.throwable?.message()).isEqualTo("Server Error")
|
||||
assertThat(error?.exception?.code()).isEqualTo(500)
|
||||
assertThat(error?.exception?.message()).isEqualTo("Server Error")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -155,8 +155,8 @@ class ApiTest {
|
|||
|
||||
val error = responseObject as? ServerError.Internal
|
||||
assertThat(error).isInstanceOf(ServerError.Internal::class.java)
|
||||
assertThat(error?.throwable?.code()).isEqualTo(500)
|
||||
assertThat(error?.throwable?.message()).isEqualTo("Server Error")
|
||||
assertThat(error?.exception?.code()).isEqualTo(500)
|
||||
assertThat(error?.exception?.message()).isEqualTo("Server Error")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -167,9 +167,9 @@ class ApiTest {
|
|||
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
|
||||
|
@ -177,9 +177,9 @@ class ApiTest {
|
|||
mockWebServer.enqueue(MockResponse().apply { socketPolicy = SocketPolicy.DISCONNECT_AFTER_REQUEST })
|
||||
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
|
||||
|
@ -189,9 +189,9 @@ class ApiTest {
|
|||
mockWebServer.enqueue(response)
|
||||
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
|
||||
|
@ -201,11 +201,11 @@ class ApiTest {
|
|||
|
||||
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
|
||||
assertThat(error).isInstanceOf(IO::class.java)
|
||||
assertThat(error?.throwable).isInstanceOf(JsonEncodingException::class.java)
|
||||
assertThat(error).isInstanceOf(IoError::class.java)
|
||||
assertThat(error?.exception).isInstanceOf(JsonEncodingException::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -32,6 +32,7 @@ import android.widget.LinearLayout
|
|||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import app.pachli.core.common.PachliError
|
||||
import app.pachli.core.common.extensions.visible
|
||||
import app.pachli.core.ui.databinding.ViewBackgroundMessageBinding
|
||||
import app.pachli.core.ui.extensions.getDrawableRes
|
||||
|
@ -99,6 +100,10 @@ class BackgroundMessageView @JvmOverloads constructor(
|
|||
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) {
|
||||
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
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.DrawableRes
|
||||
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.ui.R
|
||||
import com.squareup.moshi.JsonDataException
|
||||
|
@ -26,6 +28,7 @@ import java.io.IOException
|
|||
import retrofit2.HttpException
|
||||
|
||||
/** @return A drawable resource to accompany the error message for this throwable */
|
||||
@DrawableRes
|
||||
fun Throwable.getDrawableRes(): Int = when (this) {
|
||||
is IOException -> R.drawable.errorphant_offline
|
||||
is HttpException -> {
|
||||
|
@ -41,15 +44,15 @@ fun Throwable.getDrawableRes(): Int = when (this) {
|
|||
/** @return A unicode-wrapped string error message for this throwable */
|
||||
fun Throwable.getErrorString(context: Context): String = (
|
||||
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 -> {
|
||||
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 {
|
||||
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)
|
||||
else -> String.format(context.getString(R.string.error_generic_fmt), localizedMessage)
|
||||
is JsonDataException -> String.format(context.getString(NR.string.error_json_data_fmt), localizedMessage)
|
||||
else -> String.format(context.getString(NR.string.error_generic_fmt), localizedMessage)
|
||||
}
|
||||
).unicodeWrap()
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">لا شيء هنا.</string>
|
||||
<string name="action_retry">أعد المحاولة</string>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">Hier ist nichts.</string>
|
||||
<string name="action_retry">Erneut versuchen</string>
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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>
|
||||
</resources>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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_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="message_empty">Nada aquí.</string>
|
||||
<string name="action_retry">Reintentar</string>
|
||||
|
@ -11,6 +8,5 @@
|
|||
<string name="action_view_profile">Perfil</string>
|
||||
<string name="action_more">Más</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>
|
||||
</resources>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">Täällä ei ole mitään.</string>
|
||||
<string name="action_retry">Yritä uudelleen</string>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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_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="message_empty">Rien ici.</string>
|
||||
<string name="action_retry">Réessayer</string>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">Tidak ada apa pun disini.</string>
|
||||
<string name="action_retry">Coba lagi</string>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">Qui non c\'è nulla.</string>
|
||||
<string name="action_retry">Riprova</string>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">何もありません。</string>
|
||||
<string name="action_retry">再試行</string>
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
<string name="action_retry">Ɛreḍ tikkelt-nniḍen</string>
|
||||
<string name="action_view_profile">Amaɣnu</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="button_done">Immed</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">Hier is niets.</string>
|
||||
<string name="action_retry">Opnieuw proberen</string>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">Nada aqui.</string>
|
||||
<string name="action_retry">Tentar novamente</string>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">Ingenting här.</string>
|
||||
<string name="action_retry">Försök igen</string>
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<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="message_empty">Nothing here.</string>
|
||||
<string name="action_retry">Retry</string>
|
||||
|
|
|
@ -34,6 +34,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.ListAdapter
|
||||
import app.pachli.core.activity.emojify
|
||||
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.show
|
||||
import app.pachli.core.common.extensions.viewBinding
|
||||
|
@ -141,7 +142,7 @@ class AccountsInListFragment : DialogFragment() {
|
|||
|
||||
launch {
|
||||
viewModel.errors.collect {
|
||||
handleError(it.throwable)
|
||||
handleError(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ class AccountsInListFragment : DialogFragment() {
|
|||
if (it is Accounts.Loaded) adapter.submitList(it.accounts)
|
||||
}.onFailure {
|
||||
binding.messageView.show()
|
||||
handleError(it.throwable)
|
||||
handleError(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,11 +197,11 @@ class AccountsInListFragment : DialogFragment() {
|
|||
}
|
||||
}.onFailure {
|
||||
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.setup(error) {
|
||||
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.show
|
||||
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.ListsError
|
||||
import app.pachli.core.data.repository.ListsRepository.Companion.compareByListTitle
|
||||
import app.pachli.core.navigation.TimelineActivityIntent
|
||||
import app.pachli.core.network.model.MastoList
|
||||
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.extensions.await
|
||||
import app.pachli.feature.lists.databinding.ActivityListsBinding
|
||||
|
@ -113,29 +111,7 @@ class ListsActivity : BaseActivity(), MenuProvider {
|
|||
|
||||
lifecycleScope.launch {
|
||||
viewModel.errors.collect { error ->
|
||||
when (error) {
|
||||
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(),
|
||||
),
|
||||
)
|
||||
}
|
||||
showMessage(error.fmt(this@ListsActivity))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,17 +196,13 @@ class ListsActivity : BaseActivity(), MenuProvider {
|
|||
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 {
|
||||
binding.listsRecycler.hide()
|
||||
binding.messageView.show()
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
|
||||
if (it is NetworkError) {
|
||||
binding.messageView.setup(BackgroundMessage.Network()) { viewModel.refresh() }
|
||||
} else {
|
||||
binding.messageView.setup(BackgroundMessage.GenericError()) { viewModel.refresh() }
|
||||
}
|
||||
binding.messageView.setup(it) { viewModel.refresh() }
|
||||
}
|
||||
|
||||
state.onSuccess { lists ->
|
||||
|
|
|
@ -155,7 +155,7 @@ class ListsForAccountFragment : DialogFragment() {
|
|||
binding.listsView.hide()
|
||||
binding.messageView.apply {
|
||||
show()
|
||||
setup(it.throwable) {
|
||||
setup(it) {
|
||||
viewModel.refresh()
|
||||
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.ListsRepository
|
||||
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.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
|
@ -67,7 +66,7 @@ class ListsForAccountViewModel @AssistedInject constructor(
|
|||
private val _listsWithMembership = MutableStateFlow<Result<ListsWithMembership, FlowError>>(Ok(ListsWithMembership.Loading))
|
||||
val listsWithMembership = _listsWithMembership.asStateFlow()
|
||||
|
||||
private val _errors = Channel<Error>()
|
||||
private val _errors = Channel<HasListId>()
|
||||
val errors = _errors.receiveAsFlow()
|
||||
|
||||
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
|
||||
* [ListsForAccountViewModel.listsWithMembership] flow
|
||||
*/
|
||||
sealed interface FlowError : ApiError
|
||||
sealed interface FlowError : Error
|
||||
|
||||
/** Asynchronous errors from network operations */
|
||||
sealed interface Error : ListsError {
|
||||
/** Failed to fetch lists, or lists containing a particular account */
|
||||
@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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.pachli.core.common.string.unicodeWrap
|
||||
import app.pachli.core.data.repository.ListsError
|
||||
import app.pachli.core.data.repository.ListsRepository
|
||||
import app.pachli.core.network.model.UserListRepliesPolicy
|
||||
|
@ -32,14 +34,20 @@ import kotlinx.coroutines.flow.getAndUpdate
|
|||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
sealed interface Error : ListsError {
|
||||
val title: String
|
||||
sealed class Error(
|
||||
@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
|
||||
|
|
Loading…
Reference in New Issue