Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Stefan Zabka
Companion App Android
Commits
60f1b86c
Commit
60f1b86c
authored
Aug 16, 2019
by
Anon
Committed by
Andreas Schildbach
Aug 17, 2019
Browse files
Implement Hatchery UI for downloading a list of apps.
parent
8a3c18a0
Changes
15
Hide whitespace changes
Inline
Side-by-side
app/src/main/java/de/ccc/events/badge/card10/Constants.kt
View file @
60f1b86c
...
...
@@ -37,3 +37,5 @@ val LIGHT_SENSOR_CHARACTERISTIC_UUID = UUID.fromString("422302f0-2342-2342-2342-
val
TIME_CHARACTERISTIC_UUID
=
UUID
.
fromString
(
"42230201-2342-2342-2342-234223422342"
)
const
val
UPDATE_CLOCK_FREQUENCY_MINS
=
5
const
val
HATCHERY_BASE_URL
=
"https://badge.team"
app/src/main/java/de/ccc/events/badge/card10/common/LoadingDialog.kt
0 → 100644
View file @
60f1b86c
/*
* Copyright by the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package
de.ccc.events.badge.card10.common
import
android.os.Bundle
import
android.view.LayoutInflater
import
android.view.ViewGroup
import
androidx.fragment.app.DialogFragment
import
de.ccc.events.badge.card10.R
class
LoadingDialog
:
DialogFragment
()
{
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?)
=
inflater
.
inflate
(
R
.
layout
.
loading_dialog
,
container
,
false
)
init
{
this
.
isCancelable
=
false
}
}
\ No newline at end of file
app/src/main/java/de/ccc/events/badge/card10/hatchery/App.kt
0 → 100644
View file @
60f1b86c
/*
* Copyright by the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package
de.ccc.events.badge.card10.hatchery
import
android.os.Parcel
import
android.os.Parcelable
data class
App
(
val
name
:
String
,
val
slug
:
String
,
val
description
:
String
,
val
download_counter
:
Int
,
val
status
:
String
,
val
revision
:
String
,
val
size_of_zip
:
Int
,
val
size_of_content
:
Int
,
val
category
:
String
)
:
Parcelable
{
constructor
(
parcel
:
Parcel
)
:
this
(
parcel
.
readString
()
!!
,
parcel
.
readString
()
!!
,
parcel
.
readString
()
!!
,
parcel
.
readInt
(),
parcel
.
readString
()
!!
,
parcel
.
readString
()
!!
,
parcel
.
readInt
(),
parcel
.
readInt
(),
parcel
.
readString
()
!!
)
{
}
override
fun
writeToParcel
(
parcel
:
Parcel
,
flags
:
Int
)
{
parcel
.
writeString
(
name
)
parcel
.
writeString
(
slug
)
parcel
.
writeString
(
description
)
parcel
.
writeInt
(
download_counter
)
parcel
.
writeString
(
status
)
parcel
.
writeString
(
revision
)
parcel
.
writeInt
(
size_of_zip
)
parcel
.
writeInt
(
size_of_content
)
parcel
.
writeString
(
category
)
}
override
fun
describeContents
():
Int
{
return
0
}
companion
object
CREATOR
:
Parcelable
.
Creator
<
App
>
{
override
fun
createFromParcel
(
parcel
:
Parcel
):
App
{
return
App
(
parcel
)
}
override
fun
newArray
(
size
:
Int
):
Array
<
App
?>
{
return
arrayOfNulls
(
size
)
}
}
}
app/src/main/java/de/ccc/events/badge/card10/hatchery/AppDetailFragment.kt
0 → 100644
View file @
60f1b86c
/*
* Copyright by the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package
de.ccc.events.badge.card10.hatchery
import
android.os.Bundle
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
androidx.fragment.app.Fragment
import
de.ccc.events.badge.card10.R
import
kotlinx.android.synthetic.main.app_detail_fragment.*
import
java.lang.IllegalStateException
class
AppDetailFragment
:
Fragment
()
{
private
lateinit
var
app
:
App
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
val
bundle
=
arguments
?:
throw
IllegalStateException
()
app
=
bundle
.
getParcelable
<
App
>(
"app"
)
?:
throw
IllegalStateException
()
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?)
=
inflater
.
inflate
(
R
.
layout
.
app_detail_fragment
,
container
,
false
)
override
fun
onViewCreated
(
view
:
View
,
savedInstanceState
:
Bundle
?)
{
label_name
.
text
=
app
.
name
label_download_count
.
text
=
getString
(
R
.
string
.
app_detail_downloads
,
app
.
download_counter
)
label_content_size
.
text
=
getString
(
R
.
string
.
app_detail_content_size
,
app
.
size_of_content
)
label_description
.
text
=
app
.
description
}
}
app/src/main/java/de/ccc/events/badge/card10/hatchery/AppListAdapter.kt
0 → 100644
View file @
60f1b86c
/*
* Copyright by the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package
de.ccc.events.badge.card10.hatchery
import
android.view.LayoutInflater
import
android.view.ViewGroup
import
androidx.recyclerview.widget.RecyclerView
class
AppListAdapter
(
val
clickListener
:
(
App
)
->
Unit
)
:
RecyclerView
.
Adapter
<
AppViewHolder
>()
{
private
var
data
=
listOf
<
App
>()
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
AppViewHolder
{
val
inflater
=
LayoutInflater
.
from
(
parent
.
context
)
return
AppViewHolder
(
inflater
,
parent
)
}
override
fun
getItemCount
():
Int
{
return
data
.
size
}
override
fun
onBindViewHolder
(
holder
:
AppViewHolder
,
position
:
Int
)
{
holder
.
bind
(
data
[
position
],
clickListener
)
}
fun
update
(
items
:
List
<
App
>)
{
data
=
items
}
}
app/src/main/java/de/ccc/events/badge/card10/hatchery/AppListFragment.kt
0 → 100644
View file @
60f1b86c
/*
* Copyright by the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package
de.ccc.events.badge.card10.hatchery
import
android.content.Context
import
android.os.AsyncTask
import
android.os.Bundle
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
androidx.appcompat.app.AlertDialog
import
androidx.fragment.app.Fragment
import
androidx.recyclerview.widget.LinearLayoutManager
import
androidx.recyclerview.widget.RecyclerView
import
de.ccc.events.badge.card10.R
import
de.ccc.events.badge.card10.common.LoadingDialog
import
kotlinx.android.synthetic.main.app_list_fragment.*
import
java.lang.ref.WeakReference
class
AppListFragment
:
Fragment
()
{
private
lateinit
var
recyclerView
:
RecyclerView
private
lateinit
var
listAdapter
:
AppListAdapter
private
lateinit
var
layoutManager
:
RecyclerView
.
LayoutManager
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?)
=
inflater
.
inflate
(
R
.
layout
.
app_list_fragment
,
container
,
false
)
override
fun
onViewCreated
(
view
:
View
,
savedInstanceState
:
Bundle
?)
{
listAdapter
=
AppListAdapter
{
app
:
App
->
onAppClicked
(
app
)
}
layoutManager
=
LinearLayoutManager
(
activity
)
recyclerView
=
list
recyclerView
.
setHasFixedSize
(
true
)
recyclerView
.
layoutManager
=
layoutManager
recyclerView
.
adapter
=
listAdapter
val
loadingDialog
=
LoadingDialog
()
loadingDialog
.
show
(
fragmentManager
,
"loading"
)
DownloadTask
(
activity
as
Context
,
listAdapter
,
loadingDialog
).
execute
()
}
private
fun
onAppClicked
(
app
:
App
)
{
val
bundle
=
Bundle
()
bundle
.
putParcelable
(
"app"
,
app
)
val
fragment
=
AppDetailFragment
()
fragment
.
arguments
=
bundle
val
fragmentManager
=
activity
?.
supportFragmentManager
?:
throw
IllegalStateException
()
fragmentManager
.
beginTransaction
()
.
replace
(
R
.
id
.
fragment_container
,
fragment
)
.
commit
()
}
private
class
DownloadTask
(
context
:
Context
,
private
val
adapter
:
AppListAdapter
,
private
val
loadingDialog
:
LoadingDialog
)
:
AsyncTask
<
Void
,
Void
,
List
<
App
>?>()
{
private
val
context
=
WeakReference
<
Context
>(
context
)
override
fun
doInBackground
(
vararg
p0
:
Void
?):
List
<
App
>?
{
val
client
=
HatcheryClient
()
return
try
{
client
.
getAppList
()
}
catch
(
e
:
HatcheryClientException
)
{
null
}
}
override
fun
onPostExecute
(
result
:
List
<
App
>?)
{
if
(
result
==
null
)
{
loadingDialog
.
dismiss
()
val
ctx
=
context
.
get
()
?:
throw
IllegalStateException
()
AlertDialog
.
Builder
(
ctx
).
setMessage
(
R
.
string
.
hatchery_error_generic
)
return
}
adapter
.
update
(
result
)
adapter
.
notifyDataSetChanged
()
loadingDialog
.
dismiss
()
}
}
}
app/src/main/java/de/ccc/events/badge/card10/hatchery/AppViewHolder.kt
0 → 100644
View file @
60f1b86c
/*
* Copyright by the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package
de.ccc.events.badge.card10.hatchery
import
android.view.LayoutInflater
import
android.view.ViewGroup
import
android.widget.TextView
import
androidx.recyclerview.widget.RecyclerView
import
de.ccc.events.badge.card10.R
class
AppViewHolder
(
inflater
:
LayoutInflater
,
parent
:
ViewGroup
)
:
RecyclerView
.
ViewHolder
(
inflater
.
inflate
(
R
.
layout
.
app_list_item
,
parent
,
false
))
{
fun
bind
(
app
:
App
,
clickListener
:
(
App
)
->
Unit
)
{
val
nameLabel
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
label_name
)
nameLabel
.
text
=
app
.
name
itemView
.
setOnClickListener
{
clickListener
(
app
)
}
}
}
app/src/main/java/de/ccc/events/badge/card10/hatchery/HatcheryClient.kt
0 → 100644
View file @
60f1b86c
/*
* Copyright by the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package
de.ccc.events.badge.card10.hatchery
import
android.util.Log
import
de.ccc.events.badge.card10.HATCHERY_BASE_URL
import
okhttp3.OkHttpClient
import
okhttp3.Request
import
okhttp3.Response
import
org.json.JSONArray
import
org.json.JSONException
private
const
val
TAG
=
"HatcheryClient"
class
HatcheryClient
{
fun
getAppList
():
List
<
App
>
{
val
client
=
OkHttpClient
()
val
request
=
Request
.
Builder
()
.
url
(
HATCHERY_BASE_URL
+
"/eggs/list/json"
)
.
build
()
val
response
:
Response
try
{
response
=
client
.
newCall
(
request
).
execute
()
}
catch
(
e
:
Exception
)
{
throw
HatcheryClientException
(
0
)
}
if
(
response
.
code
!=
200
)
{
throw
HatcheryClientException
(
response
.
code
)
}
val
body
=
response
.
body
?.
string
()
?:
""
val
resultList
=
mutableListOf
<
App
>()
try
{
val
responseJson
=
JSONArray
(
body
)
for
(
i
in
0
until
responseJson
.
length
())
{
val
item
=
responseJson
.
getJSONObject
(
i
)
resultList
.
add
(
App
(
name
=
item
.
getString
(
"name"
),
slug
=
item
.
getString
(
"slug"
),
description
=
item
.
getString
(
"description"
),
download_counter
=
item
.
getInt
(
"download_counter"
),
status
=
item
.
getString
(
"status"
),
revision
=
item
.
getString
(
"revision"
),
size_of_zip
=
item
.
getInt
(
"size_of_zip"
),
size_of_content
=
item
.
getInt
(
"size_of_content"
),
category
=
item
.
getString
(
"category"
)
)
)
}
}
catch
(
e
:
JSONException
)
{
Log
.
e
(
TAG
,
"Error parsing JSON: ${e.message}"
)
throw
HatcheryClientException
(
0
)
}
return
resultList
}
}
app/src/main/java/de/ccc/events/badge/card10/hatchery/HatcheryClientException.kt
0 → 100644
View file @
60f1b86c
/*
* Copyright by the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package
de.ccc.events.badge.card10.hatchery
import
java.lang.Exception
class
HatcheryClientException
(
val
httpCode
:
Int
)
:
Exception
()
app/src/main/res/layout/app_detail_fragment.xml
0 → 100644
View file @
60f1b86c
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:padding=
"@dimen/activity_padding"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
app:layout_constraintTop_toTopOf=
"parent"
android:id=
"@+id/container_header"
>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
android:textStyle=
"bold"
android:id=
"@+id/label_name"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@id/label_name"
android:id=
"@+id/label_download_count"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@id/label_download_count"
android:id=
"@+id/label_content_size"
/>
<Button
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
android:id=
"@+id/button_download"
android:text=
"@string/app_detail_button_download"
android:enabled=
"false"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@id/container_header"
android:layout_marginTop=
"@dimen/app_detail_description_margin"
android:id=
"@+id/label_description"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
app/src/main/res/layout/app_list_fragment.xml
0 → 100644
View file @
60f1b86c
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:id=
"@+id/list"
/>
\ No newline at end of file
app/src/main/res/layout/app_list_item.xml
0 → 100644
View file @
60f1b86c
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"match_parent"
android:layout_height=
"@dimen/default_list_item_height"
>
<TextView
android:id=
"@+id/label_name"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"start"
android:paddingLeft=
"@dimen/default_list_item_margin_side"
android:textStyle=
"bold"
/>
</LinearLayout>
\ No newline at end of file
app/src/main/res/layout/loading_dialog.xml
0 → 100644
View file @
60f1b86c
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:padding=
"@dimen/loading_dialog_padding"
>
<ProgressBar
android:layout_width=
"@dimen/loading_dialog_progress"
android:layout_height=
"@dimen/loading_dialog_progress"
android:layout_gravity=
"center"
android:indeterminate=
"true"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:layout_marginTop=
"@dimen/loading_dialog_text_margin"
android:text=
"@string/loading_dialog_loading"
/>